Example #1
0
/*  Common code for two user-visible routines to share. 
    Errors here result in memory leaks, but errors here
    are serious (making aranges unusable) so we assume
    callers will not repeat the error often or mind the leaks.
*/
static int
dwarf_get_aranges_list(Dwarf_Debug dbg,
    Dwarf_Chain  * chain_out,
    Dwarf_Signed * chain_count_out,
    Dwarf_Error  * error)
{
    /* Sweeps through the arange. */
    Dwarf_Small *arange_ptr = 0;
    Dwarf_Small *arange_ptr_start = 0;

    /*  Start of arange header.  Used for rounding offset of arange_ptr
        to twice the tuple size.  Libdwarf requirement. */
    Dwarf_Small *header_ptr = 0;

    /*  Version of .debug_aranges header. */
    Dwarf_Half version = 0;

    /*  Offset of current set of aranges into .debug_info. */
    Dwarf_Off info_offset = 0;

    /*  Size in bytes of addresses in target. */
    Dwarf_Small address_size = 0;

    /*  Size in bytes of segment offsets in target. */
    Dwarf_Small segment_size = 0;

    /*  Count of total number of aranges. */
    Dwarf_Unsigned arange_count = 0;

    Dwarf_Arange arange = 0;

    /*  Used to chain Dwarf_Aranges structs. */
    Dwarf_Chain curr_chain = NULL;
    Dwarf_Chain prev_chain = NULL;
    Dwarf_Chain head_chain = NULL;
    if (!dbg->de_debug_aranges.dss_size) {
        return (DW_DLV_NO_ENTRY);
    }


    arange_ptr = dbg->de_debug_aranges.dss_data;
    arange_ptr_start = arange_ptr;
    do {
        /* Length of current set of aranges. */
        Dwarf_Unsigned length = 0;
        Dwarf_Small remainder = 0;
        Dwarf_Small *arange_ptr_past_end = 0;
        Dwarf_Unsigned range_entry_size = 0;

        int local_length_size;

        /*REFERENCED*/ /* Not used in this instance of the macro */
        int local_extension_size = 0;

        header_ptr = arange_ptr;

        /* READ_AREA_LENGTH updates arange_ptr for consumed bytes */
        READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned,
            arange_ptr, local_length_size,
            local_extension_size);
        arange_ptr_past_end = arange_ptr + length;


        READ_UNALIGNED(dbg, version, Dwarf_Half,
            arange_ptr, sizeof(Dwarf_Half));
        arange_ptr += sizeof(Dwarf_Half);
        length = length - sizeof(Dwarf_Half);
        if (version != CURRENT_VERSION_STAMP) {
            _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR);
            return (DW_DLV_ERROR);
        }

        READ_UNALIGNED(dbg, info_offset, Dwarf_Off,
            arange_ptr, local_length_size);
        arange_ptr += local_length_size;
        length = length - local_length_size;
        /* This applies to debug_info only, not to debug_types. */
        if (info_offset >= dbg->de_debug_info.dss_size) {
            FIX_UP_OFFSET_IRIX_BUG(dbg, info_offset,
                "arange info offset.a");
            if (info_offset >= dbg->de_debug_info.dss_size) {
                _dwarf_error(dbg, error, DW_DLE_ARANGE_OFFSET_BAD);
                return (DW_DLV_ERROR);
            }
        }

        address_size = *(Dwarf_Small *) arange_ptr;
        if(address_size  > sizeof(Dwarf_Addr)) {
            _dwarf_error(dbg, error, DW_DLE_ADDRESS_SIZE_ERROR);
            return DW_DLV_ERROR;
        }
        if(address_size  ==  0) {
            _dwarf_error(dbg, error, DW_DLE_ADDRESS_SIZE_ERROR);
            return DW_DLV_ERROR;
        }
        /*  It is not an error if the sizes differ.
            Unusual, but not an error. */
        arange_ptr = arange_ptr + sizeof(Dwarf_Small);
        length = length - sizeof(Dwarf_Small);

        /*  Even DWARF2 had a segment_size field here, meaning
            size in bytes of a segment descriptor on the target
            system. */
        segment_size = *(Dwarf_Small *) arange_ptr;
        if(segment_size > sizeof(Dwarf_Addr)) {
            _dwarf_error(dbg, error, DW_DLE_SEGMENT_SIZE_BAD);
            return (DW_DLV_ERROR);
        }
        arange_ptr = arange_ptr + sizeof(Dwarf_Small);
        length = length - sizeof(Dwarf_Small);

        range_entry_size = 2*address_size + segment_size;
        /* Round arange_ptr offset to next multiple of address_size. */
        remainder = (Dwarf_Unsigned) (arange_ptr - header_ptr) %
            (range_entry_size);
        if (remainder != 0) {
            arange_ptr = arange_ptr + (2 * address_size) - remainder;
            length = length - ((2 * address_size) - remainder);
        }
        do {
            Dwarf_Addr range_address = 0;
            Dwarf_Unsigned segment_selector = 0;
            Dwarf_Unsigned range_length = 0;
            /*  For segmented address spaces, the first field to
                read is a segment selector (new in DWARF4).
                Surprising since the segment_size was always there
                in the table header! */
            if(version == 4 && segment_size != 0) {
                READ_UNALIGNED(dbg, segment_selector, Dwarf_Unsigned,
                    arange_ptr, segment_size);
                arange_ptr += address_size;
                length = length - address_size;
            }

            READ_UNALIGNED(dbg, range_address, Dwarf_Addr,
                arange_ptr, address_size);
            arange_ptr += address_size;
            length = length - address_size;

            READ_UNALIGNED(dbg, range_length, Dwarf_Unsigned,
                arange_ptr, address_size);
            arange_ptr += address_size;
            length = length - address_size;

            { 
                /*  We used to suppress all-zero entries, but
                    now we return all aranges entries so we show
                    the entire content.  March 31, 2010. */

                arange = (Dwarf_Arange)
                    _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1);
                if (arange == NULL) {
                    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
                    return (DW_DLV_ERROR);
                }

                arange->ar_segment_selector = segment_selector;
                arange->ar_segment_selector_size = segment_size;
                arange->ar_address = range_address;
                arange->ar_length = range_length;
                arange->ar_info_offset = info_offset;
                arange->ar_dbg = dbg;
                arange_count++;

                curr_chain = (Dwarf_Chain)
                    _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
                if (curr_chain == NULL) {
                    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
                    return (DW_DLV_ERROR);
                }

                curr_chain->ch_item = arange;
                if (head_chain == NULL)
                    head_chain = prev_chain = curr_chain;
                else {
                    prev_chain->ch_next = curr_chain;
                    prev_chain = curr_chain;
                }
            }
            /*  The current set of ranges is terminated by
                range_address 0 and range_length 0, but that
                does not necessarily terminate the ranges for this CU! 
                There can be multiple sets in that DWARF
                does not explicitly forbid multiple sets. 
                DWARF2,3,4 section 7.20 
                We stop short to avoid overrun of the end of the CU.  */
              
        } while (arange_ptr_past_end >= (arange_ptr + range_entry_size));

        /*  A compiler could emit some padding bytes here. dwarf2/3
            (dwarf4 sec 7.20) does not clearly make extra padding 
            bytes illegal. */
        if (arange_ptr_past_end < arange_ptr) {
            char buf[200];
            Dwarf_Unsigned pad_count = arange_ptr - arange_ptr_past_end;
            Dwarf_Unsigned offset = arange_ptr - arange_ptr_start;
            snprintf(buf,sizeof(buf),"DW_DLE_ARANGE_LENGTH_BAD."
                " 0x%" DW_PR_XZEROS DW_PR_DUx 
                " pad bytes at offset 0x%" DW_PR_XZEROS DW_PR_DUx 
                " in .debug_aranges",
                pad_count, offset);
            dwarf_insert_harmless_error(dbg,buf);
        }
        /*  For most compilers, arange_ptr == arange_ptr_past_end at
            this point. But not if there were padding bytes */
        arange_ptr = arange_ptr_past_end;
    } while (arange_ptr <
        dbg->de_debug_aranges.dss_data + dbg->de_debug_aranges.dss_size);

    if (arange_ptr !=
        dbg->de_debug_aranges.dss_data + dbg->de_debug_aranges.dss_size) {
        _dwarf_error(dbg, error, DW_DLE_ARANGE_DECODE_ERROR);
        return (DW_DLV_ERROR);
    }
    *chain_out = head_chain;
    *chain_count_out = arange_count;
    return DW_DLV_OK;
}
Example #2
0
/*
    This function returns DW_DLV_OK if it succeeds
    and DW_DLV_ERR or DW_DLV_OK otherwise.
    count is set to the number of addresses in the
    .debug_aranges section. 
    For each address, the corresponding element in
    an array is set to the address itself(aranges) and
    the section offset (offsets).
    Must be identical in most aspects to
        dwarf_get_aranges!
*/
int
_dwarf_get_aranges_addr_offsets(Dwarf_Debug dbg,
    Dwarf_Addr ** addrs,
    Dwarf_Off ** offsets,
    Dwarf_Signed * count,
    Dwarf_Error * error)
{
    /* Sweeps the .debug_aranges section. */
    Dwarf_Small *arange_ptr = 0;
    Dwarf_Small *arange_start_ptr = 0;

    /* 
       Start of arange header.  Used for rounding offset of arange_ptr
       to twice the tuple size.  Libdwarf requirement. */
    Dwarf_Small *header_ptr = 0;

    /* Length of current set of aranges. */
    Dwarf_Unsigned length = 0;

    /* Version of .debug_aranges header. */
    Dwarf_Half version = 0;

    /* Offset of current set of aranges into .debug_info. */
    Dwarf_Off info_offset = 0;

    /* Size in bytes of addresses in target. */
    Dwarf_Small address_size = 0;

    /* Size in bytes of segment offsets in target. */
    Dwarf_Small segment_size = 0;

    Dwarf_Small remainder = 0;

    /* Count of total number of aranges. */
    Dwarf_Unsigned arange_count = 0;

    /* Start address of arange. */
    Dwarf_Addr range_address = 0;

    /* Length of arange. */
    Dwarf_Unsigned range_length = 0;

    Dwarf_Arange arange = 0;

    Dwarf_Unsigned i = 0;

    /* Used to chain Dwarf_Aranges structs. */
    Dwarf_Chain curr_chain = NULL;
    Dwarf_Chain prev_chain = NULL;
    Dwarf_Chain head_chain = NULL;

    Dwarf_Addr *arange_addrs = 0;
    Dwarf_Off *arange_offsets = 0;

    int res = DW_DLV_ERROR;

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

    if (error != NULL)
        *error = NULL;

    if (dbg == NULL) {
        _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
        return (DW_DLV_ERROR);
    }

    res = _dwarf_load_section(dbg, &dbg->de_debug_aranges,error);
    if (res != DW_DLV_OK) {
        return res;
    }

    arange_ptr = dbg->de_debug_aranges.dss_data;
    do {
        int local_length_size = 0;

         /*REFERENCED*/ /* Not used in this instance of the macro */
        int local_extension_size = 0;

        header_ptr = arange_ptr;

        /* READ_AREA_LENGTH updates arange_ptr for consumed bytes */
        READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned,
            arange_ptr, local_length_size,
            local_extension_size);

        READ_UNALIGNED(dbg, version, Dwarf_Half,
            arange_ptr, sizeof(Dwarf_Half));
        arange_ptr += sizeof(Dwarf_Half);
        length = length - sizeof(Dwarf_Half);
        if (version != CURRENT_VERSION_STAMP) {
            _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR);
            return (DW_DLV_ERROR);
        }

        READ_UNALIGNED(dbg, info_offset, Dwarf_Off,
            arange_ptr, local_length_size);
        arange_ptr += local_length_size;
        length = length - local_length_size;
        if (info_offset >= dbg->de_debug_info.dss_size) {
            FIX_UP_OFFSET_IRIX_BUG(dbg, info_offset,
                "arange info offset.b");
            if (info_offset >= dbg->de_debug_info.dss_size) {
                _dwarf_error(dbg, error, DW_DLE_ARANGE_OFFSET_BAD);
                return (DW_DLV_ERROR);
            }
        }

        address_size = *(Dwarf_Small *) arange_ptr;
        arange_ptr = arange_ptr + sizeof(Dwarf_Small);
        length = length - sizeof(Dwarf_Small);

        segment_size = *(Dwarf_Small *) arange_ptr;
        arange_ptr = arange_ptr + sizeof(Dwarf_Small);
        length = length - sizeof(Dwarf_Small);
        if (segment_size != 0) {
            _dwarf_error(dbg, error, DW_DLE_SEGMENT_SIZE_BAD);
            return (DW_DLV_ERROR);
        }

        /* Round arange_ptr offset to next multiple of address_size. */
        remainder = (Dwarf_Unsigned) (arange_ptr - header_ptr) %
            (2 * address_size);
        if (remainder != 0) {
            arange_ptr = arange_ptr + (2 * address_size) - remainder;
            length = length - ((2 * address_size) - remainder);
        }

        do {
            arange_start_ptr = arange_ptr;
            READ_UNALIGNED(dbg, range_address, Dwarf_Addr,
                arange_ptr, dbg->de_pointer_size);
            arange_ptr += dbg->de_pointer_size;
            length = length - dbg->de_pointer_size;

            READ_UNALIGNED(dbg, range_length, Dwarf_Unsigned,
                arange_ptr, local_length_size);
            arange_ptr += local_length_size;
            length = length - local_length_size;

            if (range_address != 0 || range_length != 0) {

                arange = (Dwarf_Arange)
                    _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1);
                if (arange == NULL) {
                    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
                    return (DW_DLV_ERROR);
                }

                arange->ar_address = range_address;
                arange->ar_length = range_length;
                arange->ar_info_offset =
                    arange_start_ptr - dbg->de_debug_aranges.dss_data;
                arange->ar_dbg = dbg;
                arange_count++;

                curr_chain = (Dwarf_Chain)
                    _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
                if (curr_chain == NULL) {
                    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
                    return (DW_DLV_ERROR);
                }

                curr_chain->ch_item = arange;
                if (head_chain == NULL)
                    head_chain = prev_chain = curr_chain;
                else {
                    prev_chain->ch_next = curr_chain;
                    prev_chain = curr_chain;
                }
            }
        } while (range_address != 0 || range_length != 0);

        if (length != 0) {
            _dwarf_error(dbg, error, DW_DLE_ARANGE_LENGTH_BAD);
            return (DW_DLV_ERROR);
        }

    } while (arange_ptr <
        dbg->de_debug_aranges.dss_data + dbg->de_debug_aranges.dss_size);

    if (arange_ptr !=
        dbg->de_debug_aranges.dss_data + dbg->de_debug_aranges.dss_size) {
        _dwarf_error(dbg, error, DW_DLE_ARANGE_DECODE_ERROR);
        return (DW_DLV_ERROR);
    }

    arange_addrs = (Dwarf_Addr *)
        _dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count);
    if (arange_addrs == NULL) {
        _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
        return (DW_DLV_ERROR);
    }
    arange_offsets = (Dwarf_Off *)
        _dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count);
    if (arange_offsets == NULL) {
        _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
        return (DW_DLV_ERROR);
    }

    curr_chain = head_chain;
    for (i = 0; i < arange_count; i++) {
        Dwarf_Arange ar = curr_chain->ch_item;

        arange_addrs[i] = ar->ar_address;
        arange_offsets[i] = ar->ar_info_offset;
        prev_chain = curr_chain;
        curr_chain = curr_chain->ch_next;
        dwarf_dealloc(dbg, ar, DW_DLA_ARANGE);
        dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
    }
    *count = arange_count;
    *offsets = arange_offsets;
    *addrs = arange_addrs;
    return (DW_DLV_OK);
}
Example #3
0
/*
    This function returns the count of the number of
    aranges in the .debug_aranges section.  It sets
    aranges to point to a block of Dwarf_Arange's 
    describing the arange's.  It returns DW_DLV_ERROR
    on error.

    Must be identical in most aspects to
        dwarf_get_aranges_addr_offsets!

*/
int
dwarf_get_aranges(Dwarf_Debug dbg,
    Dwarf_Arange ** aranges,
    Dwarf_Signed * returned_count, Dwarf_Error * error)
{
    /* Sweeps the .debug_aranges section. */
    Dwarf_Small *arange_ptr = 0;

    /* Start of arange header.  Used for rounding offset of arange_ptr
       to twice the tuple size.  Libdwarf requirement. */
    Dwarf_Small *header_ptr = 0;

    /* Version of .debug_aranges header. */
    Dwarf_Half version = 0;

    /* Offset of current set of aranges into .debug_info. */
    Dwarf_Off info_offset = 0;

    /* Size in bytes of addresses in target. */
    Dwarf_Small address_size = 0;

    /* Size in bytes of segment offsets in target. */
    Dwarf_Small segment_size = 0;

    Dwarf_Small remainder = 0;

    /* Count of total number of aranges. */
    Dwarf_Unsigned arange_count = 0;

    /* Start address of arange. */
    Dwarf_Addr range_address = 0;

    /* Length of arange. */
    Dwarf_Unsigned range_length = 0;

    Dwarf_Arange arange, *arange_block = 0;

    Dwarf_Unsigned i = 0;

    /* Used to chain Dwarf_Aranges structs. */
    Dwarf_Chain curr_chain = NULL;
    Dwarf_Chain prev_chain = NULL;
    Dwarf_Chain head_chain = NULL;

    int res = DW_DLV_ERROR;

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

    if (dbg == NULL) {
        _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
        return (DW_DLV_ERROR);
    }

    res = _dwarf_load_section(dbg, &dbg->de_debug_aranges, error);
    if (res != DW_DLV_OK) {
        return res;
    }

    arange_ptr = dbg->de_debug_aranges.dss_data;
    do {
        /* Length of current set of aranges. */
        Dwarf_Unsigned length;
        Dwarf_Small *arange_ptr_past_end = 0;

        int local_length_size;

         /*REFERENCED*/ /* Not used in this instance of the macro */
        int local_extension_size;

        header_ptr = arange_ptr;

        /* READ_AREA_LENGTH updates arange_ptr for consumed bytes */
        READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned,
            arange_ptr, local_length_size,
            local_extension_size);
        arange_ptr_past_end = arange_ptr + length;


        READ_UNALIGNED(dbg, version, Dwarf_Half,
            arange_ptr, sizeof(Dwarf_Half));
        arange_ptr += sizeof(Dwarf_Half);
        length = length - sizeof(Dwarf_Half);
        if (version != CURRENT_VERSION_STAMP) {
            _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR);
            return (DW_DLV_ERROR);
        }

        READ_UNALIGNED(dbg, info_offset, Dwarf_Off,
            arange_ptr, local_length_size);
        arange_ptr += local_length_size;
        length = length - local_length_size;
        if (info_offset >= dbg->de_debug_info.dss_size) {
            FIX_UP_OFFSET_IRIX_BUG(dbg, info_offset,
                "arange info offset.a");
            if (info_offset >= dbg->de_debug_info.dss_size) {
                _dwarf_error(dbg, error, DW_DLE_ARANGE_OFFSET_BAD);
                return (DW_DLV_ERROR);
            }
        }

        address_size = *(Dwarf_Small *) arange_ptr;
#ifdef notdef
        /* It is not an error if the sizes differ.
           Unusual, but not an error. */
        if (address_size != dbg->de_pointer_size) {
            /* Internal error of some kind */
            _dwarf_error(dbg, error, DW_DLE_BADBITC);
            return (DW_DLV_ERROR);
        }
#endif
        arange_ptr = arange_ptr + sizeof(Dwarf_Small);
        length = length - sizeof(Dwarf_Small);

        segment_size = *(Dwarf_Small *) arange_ptr;
        arange_ptr = arange_ptr + sizeof(Dwarf_Small);
        length = length - sizeof(Dwarf_Small);
        if (segment_size != 0) {
            _dwarf_error(dbg, error, DW_DLE_SEGMENT_SIZE_BAD);
            return (DW_DLV_ERROR);
        }

        /* Round arange_ptr offset to next multiple of address_size. */
        remainder = (Dwarf_Unsigned) (arange_ptr - header_ptr) %
            (2 * address_size);
        if (remainder != 0) {
            arange_ptr = arange_ptr + (2 * address_size) - remainder;
            length = length - ((2 * address_size) - remainder);
        }

        do {
            READ_UNALIGNED(dbg, range_address, Dwarf_Addr,
                arange_ptr, address_size);
            arange_ptr += address_size;
            length = length - address_size;

            READ_UNALIGNED(dbg, range_length, Dwarf_Unsigned,
                arange_ptr, address_size);
            arange_ptr += address_size;
            length = length - address_size;

            if (range_address != 0 || range_length != 0) {

                arange = (Dwarf_Arange)
                    _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1);
                if (arange == NULL) {
                    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
                    return (DW_DLV_ERROR);
                }

                arange->ar_address = range_address;
                arange->ar_length = range_length;
                arange->ar_info_offset = info_offset;
                arange->ar_dbg = dbg;
                arange_count++;

                curr_chain = (Dwarf_Chain)
                    _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
                if (curr_chain == NULL) {
                    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
                    return (DW_DLV_ERROR);
                }

                curr_chain->ch_item = arange;
                if (head_chain == NULL)
                    head_chain = prev_chain = curr_chain;
                else {
                    prev_chain->ch_next = curr_chain;
                    prev_chain = curr_chain;
                }
            }
        } while (range_address != 0 || range_length != 0);

        /* A compiler could emit some padding bytes here. dwarf2/3
           (dwarf3 draft8 sec 7.20) does not clearly make extra padding 
           bytes illegal. */
        if (arange_ptr_past_end < arange_ptr) {
            _dwarf_error(dbg, error, DW_DLE_ARANGE_LENGTH_BAD);
            return (DW_DLV_ERROR);
        }
        /* For most compilers, arange_ptr == arange_ptr_past_end at
           this point. But not if there were padding bytes */
        arange_ptr = arange_ptr_past_end;

    } while (arange_ptr <
        dbg->de_debug_aranges.dss_data + dbg->de_debug_aranges.dss_size);

    if (arange_ptr !=
        dbg->de_debug_aranges.dss_data + dbg->de_debug_aranges.dss_size) {
        _dwarf_error(dbg, error, DW_DLE_ARANGE_DECODE_ERROR);
        return (DW_DLV_ERROR);
    }

    arange_block = (Dwarf_Arange *)
        _dwarf_get_alloc(dbg, DW_DLA_LIST, arange_count);
    if (arange_block == NULL) {
        _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
        return (DW_DLV_ERROR);
    }

    curr_chain = head_chain;
    for (i = 0; i < arange_count; i++) {
        *(arange_block + i) = curr_chain->ch_item;
        prev_chain = curr_chain;
        curr_chain = curr_chain->ch_next;
        dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
    }

    *aranges = arange_block;
    *returned_count = (arange_count);
    return DW_DLV_OK;
}
Example #4
0
/* Sweeps the complete  section.  */
int
_dwarf_internal_get_pubnames_like_data(Dwarf_Debug dbg,
    Dwarf_Small * section_data_ptr,
    Dwarf_Unsigned section_length,
    Dwarf_Global ** globals,
    Dwarf_Signed * return_count,
    Dwarf_Error * error,
    int context_code,
    int global_code,
    int length_err_num,
    int version_err_num)
{
    Dwarf_Small *pubnames_like_ptr = 0;
    Dwarf_Small *section_end_ptr = section_data_ptr +section_length;

    /*  Points to the context for the current set of global names, and
        contains information to identify the compilation-unit that the
        set refers to. */
    Dwarf_Global_Context pubnames_context = 0;

    Dwarf_Half version = 0;

    /*  Offset from the start of compilation-unit for the current
        global. */
    Dwarf_Off die_offset_in_cu = 0;

    Dwarf_Unsigned global_count = 0;

    /* Points to the current global read. */
    Dwarf_Global global = 0;

    /*  Used to chain the Dwarf_Global_s structs for creating contiguous
        list of pointers to the structs. */
    Dwarf_Chain curr_chain = 0;
    Dwarf_Chain prev_chain = 0;
    Dwarf_Chain head_chain = 0;

    /* Points to contiguous block of Dwarf_Global's to be returned. */
    Dwarf_Global *ret_globals = 0;

    /* Temporary counter. */
    Dwarf_Unsigned i = 0;

    if (dbg == NULL) {
        _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
        return (DW_DLV_ERROR);
    }
    /* We will eventually need the .debug_info data. Load it now. */
    if (!dbg->de_debug_info.dss_data) {
        int res = _dwarf_load_debug_info(dbg, error);

        if (res != DW_DLV_OK) {
            return res;
        }
    }
    if (section_data_ptr == NULL) {
        return (DW_DLV_NO_ENTRY);
    }
    pubnames_like_ptr = section_data_ptr;
    do {
        Dwarf_Unsigned length = 0;
        int local_extension_size = 0;
        int local_length_size = 0;

        /*  Some compilers emit padding at the end of each cu's area.
            pubnames_ptr_past_end_cu records the true area end for the
            pubnames(like) content of a cu.
            Essentially the length in the header and the 0
            terminator of the data are redundant information. The
            dwarf2/3 spec does not mention what to do if the length is
            past the 0 terminator. So we take any bytes left after the 0
            as padding and ignore them. */
        Dwarf_Small *pubnames_ptr_past_end_cu = 0;


        pubnames_context = (Dwarf_Global_Context)
            _dwarf_get_alloc(dbg, context_code, 1);
        if (pubnames_context == NULL) {
            _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
        return (DW_DLV_ERROR);
        }
        /*  READ_AREA_LENGTH updates pubnames_like_ptr for consumed
            bytes. */
        READ_AREA_LENGTH_CK(dbg, length, Dwarf_Unsigned,
            pubnames_like_ptr, local_length_size,
            local_extension_size,error,section_length,section_end_ptr);
        pubnames_context->pu_length_size = local_length_size;
        pubnames_context->pu_extension_size = local_extension_size;
        pubnames_context->pu_dbg = dbg;

        pubnames_ptr_past_end_cu = pubnames_like_ptr + length;

        READ_UNALIGNED_CK(dbg, version, Dwarf_Half,
            pubnames_like_ptr, DWARF_HALF_SIZE,
            error,section_end_ptr);
        pubnames_like_ptr += DWARF_HALF_SIZE;
        /* ASSERT: DW_PUBNAMES_VERSION2 == DW_PUBTYPES_VERSION2 */
        if (version != DW_PUBNAMES_VERSION2) {
            _dwarf_error(dbg, error, version_err_num);
            return (DW_DLV_ERROR);
        }

        /* Offset of CU header in debug section. */
        READ_UNALIGNED_CK(dbg, pubnames_context->pu_offset_of_cu_header,
            Dwarf_Off, pubnames_like_ptr,
            pubnames_context->pu_length_size,
            error,section_end_ptr);
        pubnames_like_ptr += pubnames_context->pu_length_size;

        FIX_UP_OFFSET_IRIX_BUG(dbg,
            pubnames_context->pu_offset_of_cu_header,
            "pubnames cu header offset");


        READ_UNALIGNED_CK(dbg, pubnames_context->pu_info_length,
            Dwarf_Unsigned, pubnames_like_ptr,
            pubnames_context->pu_length_size,
            error,section_end_ptr);
        pubnames_like_ptr += pubnames_context->pu_length_size;

        if (pubnames_like_ptr > (section_data_ptr + section_length)) {
            _dwarf_error(dbg, error, length_err_num);
            return (DW_DLV_ERROR);
        }

        /*  Read initial offset (of DIE within CU) of a pubname, final
            entry is not a pair, just a zero offset. */
        READ_UNALIGNED_CK(dbg, die_offset_in_cu, Dwarf_Off,
            pubnames_like_ptr,
            pubnames_context->pu_length_size,
            error,section_end_ptr);
        pubnames_like_ptr += pubnames_context->pu_length_size;
        FIX_UP_OFFSET_IRIX_BUG(dbg,
            die_offset_in_cu, "offset of die in cu");

        /* Loop thru pairs. DIE off with CU followed by string. */
        while (die_offset_in_cu != 0) {
            int res;

            /*  Already read offset, pubnames_like_ptr now points to the
                string. */
            global =
                (Dwarf_Global) _dwarf_get_alloc(dbg, global_code, 1);
            if (global == NULL) {
                _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
                return (DW_DLV_ERROR);
            }
            global_count++;

            global->gl_context = pubnames_context;

            global->gl_named_die_offset_within_cu = die_offset_in_cu;

            global->gl_name = pubnames_like_ptr;

            res = _dwarf_check_string_valid(dbg,section_data_ptr,
                pubnames_like_ptr,section_end_ptr,
                DW_DLE_STRING_OFF_END_PUBNAMES_LIKE,error);
            if (res != DW_DLV_OK) {
                return res;
            }
            pubnames_like_ptr = pubnames_like_ptr +
                strlen((char *) pubnames_like_ptr) + 1;

            /* Finish off current entry chain */
            curr_chain =
                (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
            if (curr_chain == NULL) {
                _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
                return (DW_DLV_ERROR);
            }

            /* Put current global on singly_linked list. */
            curr_chain->ch_item = (Dwarf_Global) global;

            if (head_chain == NULL)
                head_chain = prev_chain = curr_chain;
            else {
                prev_chain->ch_next = curr_chain;
                prev_chain = curr_chain;
            }

            /* Fead offset for the *next* entry */
            READ_UNALIGNED_CK(dbg, die_offset_in_cu, Dwarf_Off,
                pubnames_like_ptr, pubnames_context->pu_length_size,
                error,section_end_ptr);
            pubnames_like_ptr += pubnames_context->pu_length_size;
            FIX_UP_OFFSET_IRIX_BUG(dbg,
                die_offset_in_cu, "offset of next die in cu");
            if (pubnames_like_ptr > (section_data_ptr + section_length)) {
                _dwarf_error(dbg, error, length_err_num);
                return (DW_DLV_ERROR);
            }
        }
        /* ASSERT: die_offset_in_cu == 0 */
        if (pubnames_like_ptr > pubnames_ptr_past_end_cu) {
            /* This is some kind of error. This simply cannot happen.
            The encoding is wrong or the length in the header for
            this cu's contribution is wrong. */
            _dwarf_error(dbg, error, length_err_num);
            return (DW_DLV_ERROR);
        }
        /*  If there is some kind of padding at the end of the section,
            as emitted by some compilers, skip over that padding and
            simply ignore the bytes thus passed-over.  With most
            compilers, pubnames_like_ptr == pubnames_ptr_past_end_cu at
            this point */
        pubnames_like_ptr = pubnames_ptr_past_end_cu;

    } while (pubnames_like_ptr < (section_data_ptr + section_length));

    /* Points to contiguous block of Dwarf_Global's. */
    ret_globals = (Dwarf_Global *)
        _dwarf_get_alloc(dbg, DW_DLA_LIST, global_count);
    if (ret_globals == NULL) {
        _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
        return (DW_DLV_ERROR);
    }

    /*  Store pointers to Dwarf_Global_s structs in contiguous block,
        and deallocate the chain. */
    curr_chain = head_chain;
    for (i = 0; i < global_count; i++) {
        *(ret_globals + i) = curr_chain->ch_item;
        prev_chain = curr_chain;
        curr_chain = curr_chain->ch_next;
        dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
    }

    *globals = ret_globals;
    *return_count = (Dwarf_Signed) global_count;
    return DW_DLV_OK;
}