1916 lines
60 KiB
C
Vendored
1916 lines
60 KiB
C
Vendored
/*
|
|
Portions Copyright (C) 2017-2021 David Anderson. 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.
|
|
*/
|
|
|
|
/* This provides access to the DWARF5 .debug_names section. */
|
|
|
|
#include <config.h>
|
|
|
|
#include <stdlib.h> /* calloc() free() */
|
|
#include <stdio.h>
|
|
#include <string.h> /* memcpy */
|
|
#if defined(_WIN32) && defined(HAVE_STDAFX_H)
|
|
#include "stdafx.h"
|
|
#endif /* HAVE_STDAFX_H */
|
|
#ifdef HAVE_STDINT_H
|
|
#include <stdint.h> /* uintptr_t */
|
|
#endif /* HAVE_STDINT_H */
|
|
|
|
#include "dwarf.h"
|
|
#include "libdwarf.h"
|
|
#include "libdwarf_private.h"
|
|
#include "dwarf_base_types.h"
|
|
#include "dwarf_safe_strcpy.h"
|
|
#include "dwarf_opaque.h"
|
|
#include "dwarf_alloc.h"
|
|
#include "dwarf_error.h"
|
|
#include "dwarf_util.h"
|
|
#include "dwarf_global.h"
|
|
#include "dwarf_debugnames.h"
|
|
#include "dwarf_string.h"
|
|
|
|
#if 0
|
|
static void
|
|
dump_bytes(char * msg,Dwarf_Small * start, long len)
|
|
{
|
|
Dwarf_Small *end = start + len;
|
|
Dwarf_Small *cur = start;
|
|
|
|
printf("%s(%ld bytes):",msg,len);
|
|
for (; cur < end; cur++) {
|
|
printf("%02x ", *cur);
|
|
}
|
|
printf("\n");
|
|
}
|
|
#endif /*0*/
|
|
#if 0
|
|
static void
|
|
dump_abbrev_record(const char *msg,
|
|
Dwarf_Unsigned abcode,
|
|
struct Dwarf_D_Abbrev_s *abb,
|
|
int line)
|
|
{
|
|
unsigned long i = 0;
|
|
|
|
printf("%s: code %lu abpairs %lu line %d \n",
|
|
msg,(unsigned long)abcode,
|
|
(unsigned long)abb->da_pairs_count,line);
|
|
for (i=0; i < abb->da_pairs_count ; ++i) {
|
|
printf(" [%lu] 0x%02lx 0x%02lx\n",
|
|
i,
|
|
(unsigned long)abb->da_idxattr[i],
|
|
(unsigned long)abb->da_form[i]);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* Encapsulates DECODE_LEB128_UWORD_LEN_CK
|
|
so the caller can free resources
|
|
in case of problems.
|
|
This updates *lp to point to next byte
|
|
*/
|
|
static int
|
|
_dwarf_read_uleb_ck(Dwarf_Small **lp,
|
|
Dwarf_Unsigned *out_p,
|
|
Dwarf_Debug dbg,
|
|
Dwarf_Error *err,
|
|
Dwarf_Small *lpend)
|
|
{
|
|
Dwarf_Small *inptr = *lp;
|
|
Dwarf_Unsigned abcode = 0;
|
|
|
|
/* The macro updates inptr */
|
|
DECODE_LEB128_UWORD_CK(inptr,
|
|
abcode,dbg,err,lpend);
|
|
*lp = inptr;
|
|
*out_p = abcode;
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
/* Encapsulates DECODE_LEB128_UWORD_CK
|
|
so the caller can free resources
|
|
in case of problems. */
|
|
static int
|
|
read_uword_ab(Dwarf_Small **lp,
|
|
Dwarf_Unsigned *out_p,
|
|
Dwarf_Debug dbg,
|
|
Dwarf_Error *err,
|
|
Dwarf_Small *lpend)
|
|
|
|
{
|
|
Dwarf_Small *inptr = *lp;
|
|
Dwarf_Unsigned out = 0;
|
|
|
|
/* The macro updates inptr */
|
|
DECODE_LEB128_UWORD_CK(inptr,
|
|
out, dbg,err,lpend);
|
|
*lp = inptr;
|
|
*out_p = out;
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
static void
|
|
free_temp_abbrevs( struct Dwarf_D_Abbrev_s * firstab)
|
|
{
|
|
struct Dwarf_D_Abbrev_s *curab = firstab;
|
|
|
|
while (curab) {
|
|
struct Dwarf_D_Abbrev_s *nxtab = 0;
|
|
|
|
nxtab = curab->da_next;
|
|
curab->da_next = 0;
|
|
free(curab);
|
|
curab = nxtab;
|
|
}
|
|
}
|
|
|
|
static int
|
|
fill_in_abbrevs_table(Dwarf_Dnames_Head dn,
|
|
Dwarf_Error * error)
|
|
{
|
|
Dwarf_Unsigned ablen = dn->dn_abbrev_table_size;
|
|
Dwarf_Small *abdata = dn->dn_abbrevs;
|
|
Dwarf_Small *tabend = abdata + ablen;
|
|
Dwarf_Small *abcur = 0;
|
|
Dwarf_Unsigned code = 0;
|
|
Dwarf_Unsigned tag = 0;
|
|
int foundabend = FALSE;
|
|
Dwarf_Unsigned abcount = 0;
|
|
struct Dwarf_D_Abbrev_s *curdab = 0;
|
|
struct Dwarf_D_Abbrev_s *firstdab = 0;
|
|
struct Dwarf_D_Abbrev_s **lastabp = &firstdab;
|
|
Dwarf_Debug dbg = dn->dn_dbg;
|
|
|
|
for (abcur = abdata; abcur < tabend; ) {
|
|
Dwarf_Unsigned attr = 0;
|
|
Dwarf_Unsigned form = 0;
|
|
Dwarf_Small *inner = 0;
|
|
Dwarf_Unsigned inroffset = 0;
|
|
int res = 0;
|
|
|
|
inroffset = abcur - abdata;
|
|
res = read_uword_ab(&abcur,&code,dbg,error,tabend);
|
|
if (res != DW_DLV_OK) {
|
|
free_temp_abbrevs(firstdab);
|
|
return res;
|
|
}
|
|
if (code == 0) {
|
|
foundabend = TRUE;
|
|
break;
|
|
}
|
|
|
|
res = read_uword_ab(&abcur,&tag,dbg,error,tabend);
|
|
if (res != DW_DLV_OK) {
|
|
free_temp_abbrevs(firstdab);
|
|
return res;
|
|
}
|
|
inner = abcur;
|
|
curdab = (struct Dwarf_D_Abbrev_s *)calloc(1,
|
|
sizeof(struct Dwarf_D_Abbrev_s));
|
|
if (!curdab) {
|
|
free_temp_abbrevs(firstdab);
|
|
firstdab = 0;
|
|
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
curdab->da_abbrev_offset = inroffset;
|
|
curdab->da_abbrev_code = code;
|
|
curdab->da_tag = tag;
|
|
abcount++;
|
|
for (;;) {
|
|
res = read_uword_ab(&inner,&attr,dbg,error,tabend);
|
|
if (res != DW_DLV_OK) {
|
|
free_temp_abbrevs(curdab);
|
|
free_temp_abbrevs(firstdab);
|
|
firstdab = 0;
|
|
return res;
|
|
}
|
|
res = read_uword_ab(&inner,&form,dbg,error,tabend);
|
|
if (res != DW_DLV_OK) {
|
|
free_temp_abbrevs(curdab);
|
|
free_temp_abbrevs(firstdab);
|
|
firstdab = 0;
|
|
return res;
|
|
}
|
|
if ( curdab->da_pairs_count ==
|
|
ABB_PAIRS_MAX) {
|
|
free_temp_abbrevs(curdab);
|
|
free_temp_abbrevs(firstdab);
|
|
_dwarf_error_string(dbg,error,
|
|
DW_DLE_DEBUG_NAMES_ABBREV_CORRUPTION,
|
|
"DW_DLE_DEBUG_NAMES_ABBREV_CORRUPTION: "
|
|
"Impossible: too many idxattr/form pairs"
|
|
"corrupt abbrevs");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
curdab->da_idxattr[curdab->da_pairs_count] =
|
|
(Dwarf_Half)attr;
|
|
curdab->da_form[curdab->da_pairs_count] =
|
|
(Dwarf_Half)form;
|
|
curdab->da_pairs_count++;
|
|
if (!attr && !form) {
|
|
/* We put the terminator into the pairs list.
|
|
done for this pair set */
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Building singly linked list. without if stmt. */
|
|
abcur = inner;
|
|
*lastabp = curdab;
|
|
lastabp = &curdab->da_next;
|
|
}
|
|
if (!foundabend) {
|
|
free_temp_abbrevs(firstdab);
|
|
_dwarf_error_string(dbg, error,
|
|
DW_DLE_DEBUG_NAMES_ABBREV_CORRUPTION,
|
|
"DW_DLE_DEBUG_NAMES_ABBREV_CORRUPTION: Never found"
|
|
"abbrev final NUL byte");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if ( abcur < tabend) {
|
|
unsigned padcount = 0;
|
|
|
|
for (; abcur < tabend; ++abcur) {
|
|
++padcount;
|
|
if (*abcur) {
|
|
dwarfstring m;
|
|
|
|
dwarfstring_constructor(&m);
|
|
dwarfstring_append_printf_u(&m,
|
|
"WARNING NON NULL debug_names "
|
|
"abbreviation pad. "
|
|
"padcount %u at ",padcount);
|
|
dwarfstring_append_printf_u(&m,
|
|
".debug_names sec_offset 0x%lx",
|
|
(uintptr_t)(abcur - dn->dn_section_data));
|
|
dwarf_insert_harmless_error(dbg,
|
|
dwarfstring_string(&m));
|
|
dwarfstring_destructor(&m);
|
|
}
|
|
}
|
|
}
|
|
{
|
|
Dwarf_Unsigned ct = 0;
|
|
struct Dwarf_D_Abbrev_s *tmpa = 0;
|
|
|
|
dn->dn_abbrev_instances =
|
|
(struct Dwarf_D_Abbrev_s *)calloc(
|
|
abcount,sizeof(struct Dwarf_D_Abbrev_s));
|
|
if (!dn->dn_abbrev_instances) {
|
|
free_temp_abbrevs(firstdab);
|
|
_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
dn->dn_abbrev_instance_count = abcount;
|
|
tmpa = firstdab;
|
|
for (ct = 0; ct < abcount; ++ct) {
|
|
struct Dwarf_D_Abbrev_s *tmpb =tmpa->da_next;
|
|
/* da_next no longer means anything */
|
|
dn->dn_abbrev_instances[ct] = *tmpa;
|
|
dn->dn_abbrev_instances[ct].da_next = 0;
|
|
free(tmpa);
|
|
tmpa = tmpb;
|
|
}
|
|
tmpa = 0;
|
|
firstdab = 0;
|
|
/* Now the list has turned into an
|
|
array. We can ignore
|
|
the list aspect. */
|
|
}
|
|
return DW_DLV_OK;
|
|
}
|
|
static int
|
|
read_uword_val(Dwarf_Debug dbg,
|
|
Dwarf_Small **ptr_in,
|
|
Dwarf_Small *endptr,
|
|
int errcode,
|
|
Dwarf_Unsigned *val_out,
|
|
Dwarf_Unsigned area_length,
|
|
Dwarf_Error *error)
|
|
{
|
|
Dwarf_Unsigned val = 0;
|
|
Dwarf_Small *ptr = *ptr_in;
|
|
|
|
READ_UNALIGNED_CK(dbg, val, Dwarf_Unsigned,
|
|
ptr, DWARF_32BIT_SIZE,
|
|
error,endptr);
|
|
ptr += DWARF_32BIT_SIZE;
|
|
if (ptr >= endptr) {
|
|
_dwarf_error(dbg, error,errcode);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
/* Some of the fields are not length fields, but
|
|
if non-zero the size will be longer than
|
|
the value, so we do the following
|
|
overall sanity check to avoid overflows. */
|
|
if (val > area_length) {
|
|
_dwarf_error(dbg, error,errcode);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
*val_out = val;
|
|
*ptr_in = ptr;
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
/* For now, check using global offset, not pointer */
|
|
#define VALIDATEOFFSET(dnm,used,m) \
|
|
do { \
|
|
if ((used) >= (dnm)->dn_next_set_offset) { \
|
|
_dwarf_error_string(dbg, error, \
|
|
DW_DLE_DEBUG_NAMES_HEADER_ERROR, \
|
|
"DW_DLE_DEBUG_NAMES_HEADER_ERROR: " \
|
|
m); \
|
|
return DW_DLV_ERROR; \
|
|
} \
|
|
} while(0)
|
|
|
|
/* Reading a .debug_names Name Index header */
|
|
static int
|
|
read_a_name_table_header(Dwarf_Dnames_Head dn,
|
|
Dwarf_Unsigned starting_offset,
|
|
Dwarf_Unsigned remaining_space,
|
|
Dwarf_Small *curptr_in,
|
|
Dwarf_Unsigned *usedspace_out,
|
|
Dwarf_Unsigned *next_offset,
|
|
Dwarf_Small *end_section,
|
|
Dwarf_Error *error)
|
|
{
|
|
Dwarf_Unsigned area_length = 0;
|
|
Dwarf_Unsigned area_max_offset = 0;
|
|
unsigned initial_length = 0; /*offset_size+local_ext */
|
|
int offset_size = 0;
|
|
int local_extension_size = 0;
|
|
Dwarf_Small *end_dnames = 0; /* 1 past local table */
|
|
Dwarf_Half version = 0;
|
|
Dwarf_Half padding = 0;
|
|
Dwarf_Unsigned comp_unit_count = 0;
|
|
Dwarf_Unsigned local_type_unit_count = 0;
|
|
Dwarf_Unsigned foreign_type_unit_count = 0;
|
|
Dwarf_Unsigned bucket_count = 0;
|
|
Dwarf_Unsigned name_count = 0;
|
|
Dwarf_Unsigned abbrev_table_size = 0; /* bytes */
|
|
Dwarf_Unsigned entry_pool_size = 0; /* bytes */
|
|
Dwarf_Unsigned augmentation_string_size = 0; /* bytes */
|
|
Dwarf_Unsigned usedspace = 0;
|
|
Dwarf_Unsigned totaloffset = 0;
|
|
int res = 0;
|
|
const char *str_utf8 = 0; /* Augmentation string */
|
|
Dwarf_Small *curptr = 0;
|
|
Dwarf_Debug dbg = dn->dn_dbg;
|
|
|
|
curptr = curptr_in;
|
|
usedspace = 0;
|
|
totaloffset = starting_offset;
|
|
/* 1 */
|
|
READ_AREA_LENGTH_CK(dbg, area_length, Dwarf_Unsigned,
|
|
curptr, offset_size,
|
|
local_extension_size,error,
|
|
remaining_space,end_section);
|
|
initial_length = offset_size+local_extension_size;
|
|
|
|
/* curptr now points past the length field */
|
|
area_max_offset = area_length + initial_length;
|
|
usedspace = initial_length;
|
|
totaloffset += initial_length;
|
|
dn->dn_offset_size = (Dwarf_Half)offset_size;
|
|
/* Two stage length test so overflow is caught. */
|
|
if (area_length > remaining_space ||
|
|
(area_length +offset_size +local_extension_size) >
|
|
remaining_space) {
|
|
_dwarf_error_string(dbg, error,
|
|
DW_DLE_DEBUG_NAMES_HEADER_ERROR,
|
|
"DW_DLE_DEBUG_NAMES_HEADER_ERROR: "
|
|
"The index table runs off the end of the .debug_names "
|
|
"section. Corrupt data.");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (area_max_offset > remaining_space) {
|
|
_dwarf_error_string(dbg, error,
|
|
DW_DLE_DEBUG_NAMES_HEADER_ERROR,
|
|
"DW_DLE_DEBUG_NAMES_HEADER_ERROR: "
|
|
"The index table runs off the end of the .debug_names "
|
|
"section... Corrupt data.");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
end_dnames = curptr + area_length;
|
|
dn->dn_unit_length = area_length + local_extension_size;
|
|
dn->dn_indextable_data_end = end_dnames;
|
|
dn->dn_next_set_offset = area_length
|
|
+ initial_length +
|
|
+ starting_offset;
|
|
|
|
/* 2 */
|
|
READ_UNALIGNED_CK(dbg, version, Dwarf_Half,
|
|
curptr, DWARF_HALF_SIZE,
|
|
error,end_dnames);
|
|
curptr += DWARF_HALF_SIZE;
|
|
usedspace += DWARF_HALF_SIZE;
|
|
totaloffset += DWARF_HALF_SIZE;
|
|
if (curptr >= end_dnames) {
|
|
_dwarf_error(dbg, error,DW_DLE_DEBUG_NAMES_HEADER_ERROR);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (version != DWARF_DNAMES_VERSION5) {
|
|
_dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
/* 3 */
|
|
READ_UNALIGNED_CK(dbg, padding, Dwarf_Half,
|
|
curptr, DWARF_HALF_SIZE,
|
|
error,end_dnames);
|
|
curptr += DWARF_HALF_SIZE;
|
|
usedspace += DWARF_HALF_SIZE;
|
|
totaloffset += DWARF_HALF_SIZE;
|
|
if (curptr >= end_dnames) {
|
|
_dwarf_error(dbg, error,DW_DLE_DEBUG_NAMES_HEADER_ERROR);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (padding) {
|
|
_dwarf_error(dbg, error,DW_DLE_DEBUG_NAMES_HEADER_ERROR);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
/* 4 */
|
|
res = read_uword_val(dbg, &curptr,
|
|
end_dnames, DW_DLE_DEBUG_NAMES_HEADER_ERROR,
|
|
&comp_unit_count,area_max_offset,error);
|
|
if (res != DW_DLV_OK) {
|
|
return res;
|
|
}
|
|
if (comp_unit_count > dn->dn_section_size) {
|
|
_dwarf_error_string(dbg,error,
|
|
DW_DLE_DEBUG_NAMES_ERROR,
|
|
"DW_DLE_DEBUG_NAMES_ERROR comp_unit_count too large");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
dn->dn_comp_unit_count = comp_unit_count;
|
|
usedspace += SIZEOFT32;
|
|
totaloffset += SIZEOFT32;
|
|
/* 5 */
|
|
res = read_uword_val(dbg, &curptr,
|
|
end_dnames, DW_DLE_DEBUG_NAMES_HEADER_ERROR,
|
|
&local_type_unit_count,area_max_offset,error);
|
|
if (res != DW_DLV_OK) {
|
|
return res;
|
|
}
|
|
if (local_type_unit_count > dn->dn_section_size) {
|
|
_dwarf_error_string(dbg,error,
|
|
DW_DLE_DEBUG_NAMES_ERROR,
|
|
"DW_DLE_DEBUG_NAMES_ERROR local_type_unit_count large");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
dn->dn_local_type_unit_count = local_type_unit_count;
|
|
usedspace += SIZEOFT32;
|
|
totaloffset += SIZEOFT32;
|
|
|
|
/* 6 */
|
|
res = read_uword_val(dbg, &curptr,
|
|
end_dnames, DW_DLE_DEBUG_NAMES_HEADER_ERROR,
|
|
&foreign_type_unit_count,area_max_offset,error);
|
|
if (res != DW_DLV_OK) {
|
|
return res;
|
|
}
|
|
if (foreign_type_unit_count > dn->dn_section_size) {
|
|
_dwarf_error_string(dbg,error,
|
|
DW_DLE_DEBUG_NAMES_ERROR,
|
|
"DW_DLE_DEBUG_NAMES_ERROR: "
|
|
"foreign_type_unit_count large");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
dn->dn_foreign_type_unit_count = foreign_type_unit_count;
|
|
usedspace += SIZEOFT32;
|
|
totaloffset += SIZEOFT32;
|
|
/* 7 */
|
|
res = read_uword_val(dbg, &curptr,
|
|
end_dnames, DW_DLE_DEBUG_NAMES_HEADER_ERROR,
|
|
&bucket_count,area_max_offset,error);
|
|
if (res != DW_DLV_OK) {
|
|
return res;
|
|
}
|
|
if (bucket_count > dn->dn_section_size) {
|
|
_dwarf_error_string(dbg,error,
|
|
DW_DLE_DEBUG_NAMES_ERROR,
|
|
"DW_DLE_DEBUG_NAMES_ERROR bucketcount too large");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
dn->dn_bucket_count = bucket_count;
|
|
usedspace += SIZEOFT32;
|
|
totaloffset += SIZEOFT32;
|
|
/* name_count gives the size of
|
|
the string-offsets and entry-offsets arrays,
|
|
and if hashes present, the size of the hashes
|
|
array. */
|
|
/* 8 */
|
|
res = read_uword_val(dbg, &curptr,
|
|
end_dnames, DW_DLE_DEBUG_NAMES_HEADER_ERROR,
|
|
&name_count,area_max_offset,error);
|
|
if (res != DW_DLV_OK) {
|
|
return res;
|
|
}
|
|
dn->dn_name_count = name_count;
|
|
if (name_count > dn->dn_section_size) {
|
|
_dwarf_error_string(dbg,error,
|
|
DW_DLE_DEBUG_NAMES_ERROR,
|
|
"DW_DLE_DEBUG_NAMES_ERROR name_count too large");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
usedspace += SIZEOFT32;
|
|
totaloffset += SIZEOFT32;
|
|
|
|
/* abbrev_table */
|
|
/* 9 */
|
|
res = read_uword_val(dbg, &curptr,
|
|
end_dnames, DW_DLE_DEBUG_NAMES_HEADER_ERROR,
|
|
&abbrev_table_size,area_max_offset,error);
|
|
if (res != DW_DLV_OK) {
|
|
return res;
|
|
}
|
|
if (abbrev_table_size > dn->dn_section_size) {
|
|
_dwarf_error_string(dbg,error,
|
|
DW_DLE_DEBUG_NAMES_ERROR,
|
|
"DW_DLE_DEBUG_NAMES_ERROR abbrev_table_size too large");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
dn->dn_abbrev_table_size = abbrev_table_size;
|
|
usedspace += SIZEOFT32;
|
|
totaloffset += SIZEOFT32;
|
|
|
|
/* 10 */
|
|
res = read_uword_val(dbg, &curptr,
|
|
end_dnames, DW_DLE_DEBUG_NAMES_HEADER_ERROR,
|
|
&augmentation_string_size,area_max_offset,error);
|
|
if (res != DW_DLV_OK) {
|
|
return res;
|
|
}
|
|
if (augmentation_string_size > dn->dn_section_size) {
|
|
_dwarf_error_string(dbg,error,
|
|
DW_DLE_DEBUG_NAMES_ERROR,
|
|
"DW_DLE_DEBUG_NAMES_ERROR augmentation string too long");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
usedspace += SIZEOFT32;
|
|
totaloffset += SIZEOFT32;
|
|
|
|
str_utf8 = (const char *) curptr;
|
|
totaloffset += augmentation_string_size;
|
|
usedspace += augmentation_string_size;
|
|
curptr += augmentation_string_size;
|
|
dn->dn_augmentation_string_size = augmentation_string_size;
|
|
if (curptr >= end_dnames) {
|
|
_dwarf_error(dbg, error,DW_DLE_DEBUG_NAMES_HEADER_ERROR);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
dn->dn_version = version;
|
|
dn->dn_abbrev_table_size = abbrev_table_size;
|
|
if (augmentation_string_size) {
|
|
/* 11. len: The string size includes zero or
|
|
more NUL bytes to be a multiple of
|
|
four bytes long. */
|
|
Dwarf_Unsigned len = augmentation_string_size;
|
|
const char *cp = 0;
|
|
const char *cpend = 0;
|
|
Dwarf_Unsigned finallen = 0;
|
|
|
|
dn->dn_augmentation_string = calloc(1,
|
|
augmentation_string_size + 1);
|
|
/* Ensures a final NUL byte */
|
|
_dwarf_safe_strcpy(dn->dn_augmentation_string,
|
|
len +1,str_utf8, len);
|
|
/* This validates a zero length string too. */
|
|
/* in LLVM0700 there is no NUL terminator there:
|
|
See DWARF5 page 144 and also ISSUE
|
|
200505.4 */
|
|
cp = dn->dn_augmentation_string;
|
|
cpend = cp + len;
|
|
/* It's null terminated now, so find the true length */
|
|
for ( ; cp<cpend; ++cp) {
|
|
if (!*cp) {
|
|
break;
|
|
}
|
|
++finallen;
|
|
}
|
|
if (len%4) {
|
|
dwarfstring m;
|
|
|
|
dwarfstring_constructor(&m);
|
|
dwarfstring_append_printf_u(&m,
|
|
"DW_DLE_DEBUG_NAMES_PAD_NON_ZERO: "
|
|
"The augmentation_string_size "
|
|
" is %u, not a multiple of four",len);
|
|
_dwarf_error_string(dbg, error,
|
|
DW_DLE_DEBUG_NAMES_PAD_NON_ZERO,
|
|
dwarfstring_string(&m));
|
|
dwarfstring_destructor(&m);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (finallen != len) {
|
|
cp = str_utf8 + finallen;
|
|
cpend = str_utf8+len;
|
|
/* Ensure that there is no corruption in
|
|
the padding. */
|
|
for ( ; cp < cpend; ++cp) {
|
|
if (*cp) {
|
|
_dwarf_error_string(dbg, error,
|
|
DW_DLE_DEBUG_NAMES_PAD_NON_ZERO,
|
|
"DW_DLE_DEBUG_NAMES_PAD_NON_ZERO: "
|
|
"padding in augmentation string not zeros");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Now we deal with the arrays following the header. */
|
|
dn->dn_cu_list = curptr;
|
|
dn->dn_cu_list_offset = usedspace;
|
|
curptr += dn->dn_offset_size * comp_unit_count;
|
|
usedspace += dn->dn_offset_size * comp_unit_count ;
|
|
totaloffset += dn->dn_offset_size * comp_unit_count ;
|
|
VALIDATEOFFSET(dn,totaloffset,"comp_unit array error");
|
|
|
|
dn->dn_local_tu_list = curptr;
|
|
dn->dn_local_tu_list_offset = usedspace;
|
|
curptr += dn->dn_offset_size *local_type_unit_count;
|
|
usedspace += dn->dn_offset_size* local_type_unit_count;
|
|
totaloffset += dn->dn_offset_size* local_type_unit_count;
|
|
VALIDATEOFFSET(dn,totaloffset,"local_type__unit array error");
|
|
|
|
dn->dn_foreign_tu_list = curptr;
|
|
dn->dn_foreign_tu_list_offset = usedspace;
|
|
curptr += sizeof(Dwarf_Sig8) * foreign_type_unit_count;
|
|
usedspace += sizeof(Dwarf_Sig8) * foreign_type_unit_count;
|
|
totaloffset += sizeof(Dwarf_Sig8)* foreign_type_unit_count;
|
|
VALIDATEOFFSET(dn,totaloffset,"foreign_type__unit array error");
|
|
|
|
dn->dn_buckets_offset = usedspace;
|
|
dn->dn_buckets = curptr;
|
|
curptr += SIZEOFT32 * bucket_count ;
|
|
usedspace += SIZEOFT32 * bucket_count;
|
|
totaloffset += SIZEOFT32 * bucket_count;
|
|
VALIDATEOFFSET(dn,totaloffset," bucket array error");
|
|
|
|
if (comp_unit_count == 1) {
|
|
Dwarf_Small *ptrx = dn->dn_cu_list;
|
|
Dwarf_Small *endptr = dn->dn_foreign_tu_list;
|
|
Dwarf_Unsigned unit_entry_size = dn->dn_offset_size;
|
|
Dwarf_Unsigned offsetval = 0;
|
|
|
|
READ_UNALIGNED_CK(dbg, offsetval, Dwarf_Unsigned,
|
|
ptrx,(unsigned long) unit_entry_size,
|
|
error,endptr);
|
|
dn->dn_single_cu = TRUE;
|
|
dn->dn_single_cu_offset = offsetval;
|
|
}
|
|
dn->dn_hash_table = curptr;
|
|
dn->dn_hash_table_offset = usedspace;
|
|
if (bucket_count) {
|
|
curptr += SIZEOFT32 * name_count;
|
|
usedspace += SIZEOFT32 * name_count;
|
|
totaloffset += SIZEOFT32 * name_count;
|
|
}
|
|
VALIDATEOFFSET(dn,totaloffset,"hashes array error");
|
|
|
|
dn->dn_string_offsets = curptr;
|
|
dn->dn_string_offsets_offset = usedspace;
|
|
curptr += dn->dn_offset_size * name_count;
|
|
usedspace += dn->dn_offset_size * name_count;
|
|
totaloffset += dn->dn_offset_size * name_count;
|
|
VALIDATEOFFSET(dn,totaloffset,"string offsets array error");
|
|
|
|
dn->dn_entry_offsets = curptr;
|
|
dn->dn_entry_offsets_offset = usedspace;
|
|
curptr += dn->dn_offset_size * name_count;
|
|
usedspace += dn->dn_offset_size * name_count;
|
|
totaloffset += dn->dn_offset_size * name_count;
|
|
VALIDATEOFFSET(dn,totaloffset,"entry offsets array error");
|
|
|
|
dn->dn_abbrevs = curptr;
|
|
dn->dn_abbrevs_offset = totaloffset;
|
|
VALIDATEOFFSET(dn,totaloffset,"abbrev table error");
|
|
curptr += dn->dn_abbrev_table_size;
|
|
usedspace += dn->dn_abbrev_table_size;
|
|
totaloffset += dn->dn_abbrev_table_size;
|
|
VALIDATEOFFSET(dn,totaloffset,"abbrev table error");
|
|
|
|
dn->dn_entry_pool = curptr;
|
|
dn->dn_entry_pool_offset = totaloffset;
|
|
if (dn->dn_next_set_offset < totaloffset) {
|
|
_dwarf_error_string(dbg, error,
|
|
DW_DLE_DEBUG_NAMES_HEADER_ERROR,
|
|
"DW_DLE_DEBUG_NAMES_HEADER_ERROR: "
|
|
"Abbrev total wrong, exceeds "
|
|
"the room available.");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
entry_pool_size = dn->dn_next_set_offset - totaloffset;
|
|
dn->dn_entry_pool_size = entry_pool_size;
|
|
curptr += entry_pool_size;
|
|
usedspace += entry_pool_size;
|
|
totaloffset += entry_pool_size;
|
|
|
|
if (totaloffset != dn->dn_next_set_offset) {
|
|
_dwarf_error_string(dbg, error,
|
|
DW_DLE_DEBUG_NAMES_HEADER_ERROR,
|
|
"DW_DLE_DEBUG_NAMES_HEADER_ERROR: "
|
|
"Final total offset does not match base "
|
|
"calculation. Logic error.");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
*usedspace_out = usedspace;
|
|
*next_offset = dn->dn_next_set_offset;
|
|
res = fill_in_abbrevs_table(dn,error);
|
|
if (res != DW_DLV_OK) {
|
|
free(dn->dn_augmentation_string);
|
|
dn->dn_augmentation_string = 0;
|
|
return res;
|
|
}
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
#define FAKE_LAST_USED 0xffffffff
|
|
|
|
/* There may be one debug index for an entire object file,
|
|
for multiple CUs or there can be individual indexes
|
|
for some CUs.
|
|
see DWARF5 6.1.1.3 Per_CU versus Per-Module Indexes.
|
|
The initial of these tables starts at offset 0.
|
|
If the starting-offset is too high for the section
|
|
return DW_DLV_NO_ENTRY */
|
|
int
|
|
dwarf_dnames_header(Dwarf_Debug dbg,
|
|
Dwarf_Off starting_offset,
|
|
Dwarf_Dnames_Head * dn_out,
|
|
Dwarf_Off * offset_of_next_table,
|
|
Dwarf_Error * error)
|
|
{
|
|
Dwarf_Unsigned remaining = 0;
|
|
Dwarf_Dnames_Head dn = 0;
|
|
Dwarf_Unsigned section_size = 0;
|
|
Dwarf_Unsigned usedspace = 0;
|
|
Dwarf_Unsigned next_offset = 0;
|
|
Dwarf_Small *start_section= 0;
|
|
Dwarf_Small *end_section = 0;
|
|
Dwarf_Small *curptr = 0;
|
|
int res = 0;
|
|
|
|
if (!dbg) {
|
|
_dwarf_error_string(dbg, error,DW_DLE_DBG_NULL,
|
|
"DW_DLE_DBG_NULL: Dwarf_Debug argument in "
|
|
"dwarf_dnames_header() "
|
|
"call is NULL");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
res = _dwarf_load_section(dbg, &dbg->de_debug_names, error);
|
|
if (res != DW_DLV_OK) {
|
|
return res;
|
|
}
|
|
section_size = dbg->de_debug_names.dss_size;
|
|
if (!section_size){
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
res = _dwarf_load_section(dbg, &dbg->de_debug_str,error);
|
|
if (res == DW_DLV_ERROR) {
|
|
return res;
|
|
}
|
|
if (starting_offset >= section_size) {
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
start_section = dbg->de_debug_names.dss_data;
|
|
curptr = start_section += starting_offset;
|
|
end_section = start_section + section_size;
|
|
dn = (Dwarf_Dnames_Head)_dwarf_get_alloc(dbg,
|
|
DW_DLA_DNAMES_HEAD, 1);
|
|
if (!dn) {
|
|
_dwarf_error_string(dbg, error, DW_DLE_ALLOC_FAIL,
|
|
"DW_DLE_ALLOC_FAIL: dwarf_get_alloc of "
|
|
"a Dwarf_Dnames_Head record failed.");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
dn->dn_magic = DWARF_DNAMES_MAGIC;
|
|
dn->dn_section_data = start_section;
|
|
dn->dn_section_size = section_size;
|
|
dn->dn_section_end = start_section + section_size;
|
|
dn->dn_dbg = dbg;
|
|
dn->dn_section_offset = starting_offset;
|
|
dn->dn_indextable_data = starting_offset + start_section;;
|
|
remaining = dn->dn_section_size - starting_offset;
|
|
res = read_a_name_table_header(dn,
|
|
starting_offset,
|
|
remaining,
|
|
curptr,
|
|
&usedspace,
|
|
&next_offset,
|
|
dn->dn_section_end,
|
|
error);
|
|
if (res == DW_DLV_ERROR) {
|
|
dwarf_dealloc_dnames(dn);
|
|
return res;
|
|
}
|
|
if (res == DW_DLV_NO_ENTRY) {
|
|
/* Impossible. A bug. Or possibly
|
|
a bunch of zero pad? */
|
|
dwarf_dealloc_dnames(dn);
|
|
return res;
|
|
}
|
|
if (usedspace > section_size) {
|
|
dwarf_dealloc_dnames(dn);
|
|
_dwarf_error_string(dbg, error,DW_DLE_DEBUG_NAMES_OFF_END,
|
|
"DW_DLE_DEBUG_NAMES_OFF_END: "
|
|
" used space > section size");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
remaining -= usedspace;
|
|
if (remaining && remaining < 15) {
|
|
/* No more content in here, just padding. Check for zero
|
|
in padding. */
|
|
curptr += usedspace;
|
|
for ( ; curptr < end_section; ++curptr) {
|
|
if (*curptr) {
|
|
/* One could argue this is a harmless error,
|
|
but for now assume it is real corruption. */
|
|
dwarf_dealloc(dbg,dn,DW_DLA_DNAMES_HEAD);
|
|
_dwarf_error_string(dbg, error,
|
|
DW_DLE_DEBUG_NAMES_PAD_NON_ZERO,
|
|
"DW_DLE_DEBUG_NAMES_PAD_NON_ZERO: "
|
|
"space at end of valid tables not zeros");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
}
|
|
}
|
|
*dn_out = dn;
|
|
*offset_of_next_table = next_offset;
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
/* Frees all the space in dn. It's up to you
|
|
to to "dn = 0;" after the call. */
|
|
static void
|
|
_dwarf_internal_dwarf_dealloc_dnames(Dwarf_Dnames_Head dn)
|
|
{
|
|
if (!dn || dn->dn_magic != DWARF_DNAMES_MAGIC) {
|
|
return;
|
|
}
|
|
free(dn->dn_augmentation_string);
|
|
dn->dn_augmentation_string = 0;
|
|
free(dn->dn_bucket_array);
|
|
dn->dn_bucket_array = 0;
|
|
free(dn->dn_abbrev_instances);
|
|
dn->dn_abbrev_instances = 0;
|
|
dn->dn_abbrev_instance_count = 0;
|
|
dn->dn_magic = 0;
|
|
}
|
|
|
|
void
|
|
dwarf_dealloc_dnames(Dwarf_Dnames_Head dn)
|
|
{
|
|
if (!dn || dn->dn_magic != DWARF_DNAMES_MAGIC) {
|
|
return;
|
|
}
|
|
_dwarf_internal_dwarf_dealloc_dnames(dn);
|
|
/* Now dn_magic 0 so the dwarf_dealloc
|
|
will just do the base record free. */
|
|
dwarf_dealloc(dn->dn_dbg,dn,DW_DLA_DNAMES_HEAD);
|
|
}
|
|
/* Frees any Dwarf_Dnames_Head_s data content that is directly
|
|
mallocd, unless such is already done. */
|
|
void
|
|
_dwarf_dnames_destructor(void *m)
|
|
{
|
|
Dwarf_Dnames_Head dn = (Dwarf_Dnames_Head)m;
|
|
if (!dn || dn->dn_magic != DWARF_DNAMES_MAGIC) {
|
|
return;
|
|
}
|
|
_dwarf_internal_dwarf_dealloc_dnames(dn);
|
|
}
|
|
|
|
/* These are the sizes/counts applicable a particular
|
|
names table (most likely the only one) in the
|
|
.debug_names section, numbers from the section
|
|
Dwarf_Dnames header.
|
|
DWARF5 section 6.1.1.2 Structure of the Name Header. */
|
|
int dwarf_dnames_sizes(Dwarf_Dnames_Head dn,
|
|
/* The counts are entry counts, not byte sizes. */
|
|
Dwarf_Unsigned * comp_unit_count,
|
|
Dwarf_Unsigned * local_type_unit_count,
|
|
Dwarf_Unsigned * foreign_type_unit_count,
|
|
Dwarf_Unsigned * bucket_count,
|
|
Dwarf_Unsigned * name_count,
|
|
|
|
/* The following are counted in bytes */
|
|
Dwarf_Unsigned * abbrev_table_size,
|
|
Dwarf_Unsigned * entry_pool_size,
|
|
Dwarf_Unsigned * augmentation_string_size,
|
|
char ** augmentation_string,
|
|
Dwarf_Unsigned * section_size,
|
|
Dwarf_Half * table_version,
|
|
Dwarf_Half * offset_size,
|
|
Dwarf_Error * error)
|
|
{
|
|
if (!dn || dn->dn_magic != DWARF_DNAMES_MAGIC) {
|
|
_dwarf_error_string(NULL, error,DW_DLE_DBG_NULL,
|
|
"DW_DLE_DBG_NULL: A call to dwarf_dnames_sizes() "
|
|
"has a NULL Dwarf_Dnames_Head or an improper one.");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (comp_unit_count) {
|
|
*comp_unit_count = dn->dn_comp_unit_count;
|
|
}
|
|
if (local_type_unit_count) {
|
|
*local_type_unit_count = dn->dn_local_type_unit_count;
|
|
}
|
|
if (foreign_type_unit_count) {
|
|
*foreign_type_unit_count = dn->dn_foreign_type_unit_count;
|
|
}
|
|
if (bucket_count) {
|
|
*bucket_count = dn->dn_bucket_count;
|
|
}
|
|
if (name_count) {
|
|
*name_count = dn->dn_name_count;
|
|
}
|
|
if (abbrev_table_size) {
|
|
*abbrev_table_size = dn->dn_abbrev_table_size;
|
|
}
|
|
if (entry_pool_size) {
|
|
*entry_pool_size = dn->dn_entry_pool_size;
|
|
}
|
|
if (augmentation_string_size) {
|
|
*augmentation_string_size = dn->dn_augmentation_string_size;
|
|
}
|
|
if (augmentation_string) {
|
|
*augmentation_string = dn->dn_augmentation_string;
|
|
}
|
|
if (section_size) {
|
|
*section_size = dn->dn_section_size;
|
|
}
|
|
if (table_version) {
|
|
*table_version = dn->dn_version;
|
|
}
|
|
if (offset_size) {
|
|
*offset_size = dn->dn_offset_size;
|
|
}
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
/* Useful for investigating errors in libdwarf or the
|
|
.debug_names section. */
|
|
int
|
|
dwarf_dnames_offsets(Dwarf_Dnames_Head dn,
|
|
Dwarf_Unsigned * header_offset,
|
|
Dwarf_Unsigned * cu_table_offset,
|
|
Dwarf_Unsigned * tu_local_offset,
|
|
Dwarf_Unsigned * foreign_tu_offset,
|
|
Dwarf_Unsigned * bucket_offset,
|
|
Dwarf_Unsigned * hashes_offset,
|
|
Dwarf_Unsigned * stringoffsets_offset,
|
|
Dwarf_Unsigned * entryoffsets_offset,
|
|
Dwarf_Unsigned * abbrev_table_offset,
|
|
Dwarf_Unsigned * entry_pool_offset,
|
|
Dwarf_Error * error)
|
|
{
|
|
if (!dn || dn->dn_magic != DWARF_DNAMES_MAGIC) {
|
|
_dwarf_error_string(NULL, error,DW_DLE_DBG_NULL,
|
|
"DW_DLE_DBG_NULL: A call to dwarf_dnames_offsets() "
|
|
"has a NULL Dwarf_Dnames_Head or an improper one.");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (header_offset) {
|
|
*header_offset = dn->dn_section_offset;
|
|
}
|
|
if (cu_table_offset) {
|
|
*cu_table_offset = dn->dn_cu_list_offset;
|
|
}
|
|
if (tu_local_offset) {
|
|
*tu_local_offset = dn->dn_local_tu_list_offset;
|
|
}
|
|
if (foreign_tu_offset) {
|
|
*foreign_tu_offset = dn->dn_foreign_tu_list_offset;
|
|
}
|
|
if (bucket_offset) {
|
|
*bucket_offset = dn->dn_buckets_offset;
|
|
}
|
|
if (hashes_offset) {
|
|
*hashes_offset = dn->dn_hash_table_offset;
|
|
}
|
|
if (stringoffsets_offset) {
|
|
*stringoffsets_offset = dn->dn_string_offsets_offset;
|
|
}
|
|
if (entryoffsets_offset) {
|
|
*entryoffsets_offset = dn->dn_entry_offsets_offset;
|
|
}
|
|
if (abbrev_table_offset) {
|
|
*abbrev_table_offset = dn->dn_abbrevs_offset;
|
|
}
|
|
if (entry_pool_offset) {
|
|
*entry_pool_offset = dn->dn_entry_pool_offset;
|
|
}
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
/* The "tu" case covers both local type units
|
|
and foreign type units.
|
|
This table is indexed starting at 0.
|
|
*/
|
|
int
|
|
dwarf_dnames_cu_table(Dwarf_Dnames_Head dn,
|
|
const char * type /* "cu", "tu" */,
|
|
Dwarf_Unsigned index_number,
|
|
Dwarf_Unsigned * offset,
|
|
Dwarf_Sig8 * sig,
|
|
Dwarf_Error * error)
|
|
{
|
|
Dwarf_Debug dbg = 0;
|
|
Dwarf_Unsigned unit_count = 0;
|
|
Dwarf_Unsigned total_count = 0;
|
|
Dwarf_Unsigned unit_entry_size = 0;
|
|
Dwarf_Small * unit_ptr = 0;
|
|
Dwarf_Unsigned foreign_count = 0;
|
|
Dwarf_Bool offset_case = TRUE;
|
|
|
|
if (!dn || dn->dn_magic != DWARF_DNAMES_MAGIC) {
|
|
_dwarf_error_string(NULL, error,DW_DLE_DEBUG_NAMES_ERROR,
|
|
"DW_DLE_DEBUG_NAMES_ERROR: "
|
|
" Dwarf_Dnames_Head is NULL or invalid pointer"
|
|
"calling dwarf_dnames_cu_table()");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
dbg = dn->dn_dbg;
|
|
if (type[0] == 'c') {
|
|
unit_ptr = dn->dn_cu_list;
|
|
unit_entry_size = dn->dn_offset_size;
|
|
unit_count = dn->dn_comp_unit_count;
|
|
total_count = unit_count;
|
|
offset_case = TRUE;
|
|
} else if (type[0] == 't') {
|
|
unit_count = dn->dn_local_type_unit_count;
|
|
foreign_count = dn->dn_foreign_type_unit_count;
|
|
total_count = unit_count + foreign_count;
|
|
if (index_number < dn->dn_local_type_unit_count) {
|
|
unit_ptr = dn->dn_local_tu_list;
|
|
unit_entry_size = dn->dn_offset_size;
|
|
offset_case = TRUE;
|
|
} else {
|
|
unit_ptr = dn->dn_foreign_tu_list;
|
|
unit_entry_size = sizeof(Dwarf_Sig8);
|
|
offset_case = FALSE;
|
|
}
|
|
} else {
|
|
_dwarf_error_string(dbg,error,DW_DLE_DEBUG_NAMES_ERROR,
|
|
"DW_DLE_DEBUG_NAMES_ERROR: "
|
|
"type string is not start with cu or tu"
|
|
"so invalid call to dwarf_dnames_cu_table()");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (index_number >= total_count) {
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
if (offset_case) {
|
|
/* CU or TU ref */
|
|
Dwarf_Unsigned offsetval = 0;
|
|
Dwarf_Small *ptr = unit_ptr +
|
|
(index_number) *unit_entry_size;
|
|
Dwarf_Small *endptr = dn->dn_indextable_data_end;
|
|
|
|
READ_UNALIGNED_CK(dbg, offsetval, Dwarf_Unsigned,
|
|
ptr, (unsigned long)unit_entry_size,
|
|
error,endptr);
|
|
if (offset) {
|
|
*offset = offsetval;
|
|
}
|
|
return DW_DLV_OK;
|
|
}
|
|
{
|
|
Dwarf_Small *ptr = unit_ptr +
|
|
(index_number -unit_count) *unit_entry_size;
|
|
if (sig) {
|
|
memcpy(sig,ptr,sizeof(*sig));
|
|
}
|
|
}
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
/* Each bucket gives the index of the first of
|
|
the name entries for the bucket
|
|
index_of_entry returns the name table entry.
|
|
indexcount returns the number of name table entries
|
|
(representing name collisions) for this bucket. */
|
|
static int
|
|
_dwarf_initialize_bucket_details(Dwarf_Dnames_Head dn,
|
|
Dwarf_Error * error)
|
|
{
|
|
Dwarf_Debug dbg = 0;
|
|
Dwarf_Unsigned i = 0;
|
|
struct Dwarf_DN_Bucket_s *curbucket = 0;
|
|
|
|
dbg = dn->dn_dbg;
|
|
if (dn->dn_bucket_array) {
|
|
return DW_DLV_OK;
|
|
}
|
|
if (!dn->dn_bucket_count) {
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
dn->dn_bucket_array = (struct Dwarf_DN_Bucket_s*)
|
|
calloc(dn->dn_bucket_count,sizeof(struct Dwarf_DN_Bucket_s));
|
|
if (!dn->dn_bucket_array) {
|
|
_dwarf_error_string(dbg,error,DW_DLE_ALLOC_FAIL,
|
|
"DW_DLE_ALLOC_FAIL: "
|
|
".debug_names bucket array could not be allocated");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
curbucket = dn->dn_bucket_array ;
|
|
for (i = 0 ; i < dn->dn_bucket_count; ++i) {
|
|
Dwarf_Unsigned offsetval = 0;
|
|
Dwarf_Small *ptr = dn->dn_buckets +
|
|
i * DWARF_32BIT_SIZE;
|
|
Dwarf_Small *endptr = dn->dn_buckets+
|
|
dn->dn_bucket_count*DWARF_32BIT_SIZE;
|
|
|
|
READ_UNALIGNED_CK(dbg, offsetval, Dwarf_Unsigned,
|
|
ptr, DWARF_32BIT_SIZE,
|
|
error,endptr);
|
|
curbucket = dn->dn_bucket_array +i;
|
|
curbucket->db_nameindex = offsetval;
|
|
}
|
|
for (i = 0; i < dn->dn_bucket_count; ) {
|
|
Dwarf_Unsigned j = 0;
|
|
|
|
curbucket = dn->dn_bucket_array+i;
|
|
if (!curbucket->db_nameindex) {
|
|
++i;
|
|
continue;
|
|
}
|
|
for (j = i+1; j < dn->dn_bucket_count; ++j) {
|
|
struct Dwarf_DN_Bucket_s *partial =
|
|
dn->dn_bucket_array+j;
|
|
|
|
if (partial->db_nameindex) {
|
|
curbucket->db_collisioncount =
|
|
partial->db_nameindex - curbucket->db_nameindex;
|
|
i = j;
|
|
break;
|
|
}
|
|
}
|
|
if (j >= dn->dn_bucket_count) {
|
|
/* Ran off end */
|
|
curbucket->db_collisioncount =
|
|
dn->dn_name_count - curbucket->db_nameindex;
|
|
if (!curbucket->db_collisioncount) {
|
|
curbucket->db_collisioncount = 1;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
int
|
|
dwarf_dnames_bucket(Dwarf_Dnames_Head dn,
|
|
Dwarf_Unsigned bucket_number,
|
|
Dwarf_Unsigned * name_index,
|
|
Dwarf_Unsigned * collision_count,
|
|
Dwarf_Error * error)
|
|
{
|
|
struct Dwarf_DN_Bucket_s *cur = 0;
|
|
int res = 0;
|
|
|
|
if (!dn || dn->dn_magic != DWARF_DNAMES_MAGIC) {
|
|
_dwarf_error_string(NULL, error,DW_DLE_DBG_NULL,
|
|
"DW_DLE_DBG_NULL: bad Head argument to "
|
|
"dwarf_dnames_bucket");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (bucket_number >= dn->dn_bucket_count) {
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
res = _dwarf_initialize_bucket_details(dn,error);
|
|
if (res == DW_DLV_ERROR) {
|
|
return res;
|
|
}
|
|
if (!dn->dn_bucket_array) {
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
cur = dn->dn_bucket_array + bucket_number;
|
|
*name_index = cur->db_nameindex;
|
|
*collision_count = cur->db_collisioncount;
|
|
return DW_DLV_OK;
|
|
}
|
|
static int
|
|
get_hash_value_number(Dwarf_Dnames_Head dn,
|
|
Dwarf_Unsigned name_index,
|
|
Dwarf_Unsigned *hash_value,
|
|
Dwarf_Error *error)
|
|
{
|
|
Dwarf_Unsigned hash_val = 0;
|
|
int res = 0;
|
|
Dwarf_Small * hashesentry = 0;
|
|
Dwarf_Small *end = 0;
|
|
|
|
if (!dn->dn_bucket_count) {
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
hashesentry = dn->dn_hash_table + (name_index-1)*DWARF_32BIT_SIZE;
|
|
end = dn->dn_hash_table + DWARF_32BIT_SIZE*(dn->dn_name_count+1);
|
|
res = read_uword_val(dn->dn_dbg,
|
|
&hashesentry,
|
|
end,
|
|
DW_DLE_DEBUG_NAMES_OFF_END,
|
|
&hash_val,
|
|
0xffffffff, /* hashes fit in 32 bits */
|
|
error);
|
|
if (res != DW_DLV_OK) {
|
|
return res;
|
|
}
|
|
*hash_value = hash_val;
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
static int
|
|
get_bucket_number(Dwarf_Dnames_Head dn,
|
|
Dwarf_Unsigned name_index,
|
|
Dwarf_Unsigned *bucket_num)
|
|
{
|
|
Dwarf_Unsigned i = 0;
|
|
|
|
if (!dn->dn_bucket_count) {
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
if (!dn->dn_bucket_array) {
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
/* Binary search would be better FIXME */
|
|
for (i = 0; i < dn->dn_bucket_count; ++i) {
|
|
Dwarf_Unsigned bindx = 0;
|
|
Dwarf_Unsigned ccount = 0;
|
|
Dwarf_Unsigned lastbindx = 0;
|
|
struct Dwarf_DN_Bucket_s *cur = dn->dn_bucket_array +i;
|
|
|
|
bindx = cur->db_nameindex;
|
|
ccount = cur->db_collisioncount;
|
|
lastbindx = ccount + bindx -1;
|
|
if (name_index > lastbindx) {
|
|
continue;
|
|
}
|
|
if (!bindx ) {
|
|
/* empty bucket */
|
|
continue;
|
|
}
|
|
if (bindx == name_index) {
|
|
*bucket_num = i;
|
|
return DW_DLV_OK;
|
|
}
|
|
if (name_index <= lastbindx) {
|
|
*bucket_num = i;
|
|
return DW_DLV_OK;
|
|
}
|
|
}
|
|
/* ? is it an error? */
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
|
|
/* We try to protect against bogus arguments,
|
|
but all we can do is check for null. */
|
|
int
|
|
dwarf_dnames_abbrevtable(Dwarf_Dnames_Head dn,
|
|
Dwarf_Unsigned index,
|
|
Dwarf_Unsigned *abbrev_offset,
|
|
Dwarf_Unsigned *abbrev_code,
|
|
Dwarf_Unsigned *abbrev_tag,
|
|
Dwarf_Unsigned array_size,
|
|
Dwarf_Half * idxattr_array,
|
|
Dwarf_Half * form_array,
|
|
Dwarf_Unsigned * attr_count)
|
|
{
|
|
struct Dwarf_D_Abbrev_s *ab = 0;
|
|
Dwarf_Unsigned abnumber = 0;
|
|
Dwarf_Unsigned abmax = 0;
|
|
|
|
if (!dn) {
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
if (!idxattr_array || !form_array) {
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
if (index >= dn->dn_abbrev_instance_count) {
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
ab = dn->dn_abbrev_instances + index;
|
|
if (abbrev_offset) {
|
|
*abbrev_offset = ab->da_abbrev_offset;
|
|
}
|
|
if (abbrev_code) {
|
|
*abbrev_code = ab->da_abbrev_code;
|
|
}
|
|
if (abbrev_tag) {
|
|
*abbrev_tag = ab->da_tag;
|
|
}
|
|
abmax = ab->da_pairs_count;
|
|
if (attr_count) {
|
|
*attr_count = abmax;
|
|
}
|
|
if (array_size < abmax) {
|
|
abmax = array_size;
|
|
}
|
|
for ( ; abnumber < abmax; ++abnumber) {
|
|
idxattr_array[abnumber] = ab->da_idxattr[abnumber];
|
|
form_array[abnumber] = ab->da_form[abnumber];
|
|
}
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
static int
|
|
_dwarf_read_abbrev_code_from_pool(Dwarf_Dnames_Head dn,
|
|
Dwarf_Unsigned entrypooloffset,
|
|
Dwarf_Unsigned *code,
|
|
Dwarf_Error *error)
|
|
{
|
|
Dwarf_Small *epool = 0;
|
|
Dwarf_Small *end = 0;
|
|
Dwarf_Debug dbg = 0;
|
|
int res = 0;
|
|
|
|
epool = dn->dn_entry_pool;
|
|
end = epool + dn->dn_entry_pool_size;
|
|
if (entrypooloffset >= dn->dn_entry_pool_size) {
|
|
_dwarf_error_string(dbg,error,DW_DLE_DEBUG_NAMES_ERROR,
|
|
"DW_DLE_DEBUG_NAMES_ERROR: "
|
|
"The entry pool offset from the names table "
|
|
" is out of bounds.");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
epool += entrypooloffset;
|
|
dbg = dn->dn_dbg;
|
|
res = _dwarf_read_uleb_ck(&epool,
|
|
code,dbg,error,end);
|
|
if (res == DW_DLV_ERROR) {
|
|
return res;
|
|
}
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
/* Starting out with a simple linear search.
|
|
Better to use a dwarf_tsearch function. */
|
|
static int
|
|
_dwarf_find_abbrev_for_code(Dwarf_Dnames_Head dn,
|
|
Dwarf_Unsigned code,
|
|
struct Dwarf_D_Abbrev_s **abbrevdata,
|
|
Dwarf_Error *error)
|
|
{
|
|
Dwarf_Unsigned i = 0;
|
|
struct Dwarf_D_Abbrev_s *ap =0;
|
|
|
|
ap = dn->dn_abbrev_instances;
|
|
for (i = 0; i < dn->dn_abbrev_instance_count; ++i,++ap) {
|
|
if (ap->da_abbrev_code == code) {
|
|
*abbrevdata = ap;
|
|
return DW_DLV_OK;
|
|
}
|
|
}
|
|
{
|
|
Dwarf_Debug dbg = 0;
|
|
dwarfstring m;
|
|
|
|
dbg = dn->dn_dbg;
|
|
dwarfstring_constructor(&m);
|
|
dwarfstring_append_printf_u(&m,
|
|
"DW_DLE_DEBUG_NAMES_ERROR: "
|
|
"The abbrev code %u",code);
|
|
dwarfstring_append_printf_u(&m,
|
|
"(0x%x) ",code);
|
|
dwarfstring_append(&m,
|
|
"from the entry pool "
|
|
"is absent from the abbrev table.");
|
|
_dwarf_error_string(dbg,error,DW_DLE_DEBUG_NAMES_ERROR,
|
|
dwarfstring_string(&m));
|
|
dwarfstring_destructor(&m);
|
|
}
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
static int
|
|
_dwarf_fill_in_attr_form(Dwarf_Dnames_Head dn,
|
|
struct Dwarf_D_Abbrev_s *abbrevdata,
|
|
Dwarf_Half *idxattr_array,
|
|
Dwarf_Half *form_array,
|
|
Dwarf_Unsigned array_size,
|
|
Dwarf_Error *error)
|
|
{
|
|
Dwarf_Unsigned limit = abbrevdata->da_pairs_count;
|
|
Dwarf_Unsigned i = 0;
|
|
Dwarf_Debug dbg = 0;
|
|
|
|
if (limit > array_size) {
|
|
limit = array_size;
|
|
}
|
|
for ( ; i < limit ; ++i) {
|
|
idxattr_array[i] = abbrevdata->da_idxattr[i];
|
|
form_array[i] = abbrevdata->da_form[i];
|
|
}
|
|
if (i < limit) {
|
|
dwarfstring m;
|
|
|
|
dbg= dn->dn_dbg;
|
|
dwarfstring_constructor(&m);
|
|
dwarfstring_append_printf_u(&m,
|
|
"DW_DLE_DEBUG_NAMES_ERROR: "
|
|
"At attr-form pair ",i);
|
|
dwarfstring_append_printf_u(&m,
|
|
", with attr-form max of %u",
|
|
abbrevdata->da_pairs_count);
|
|
dwarfstring_append_printf_u(&m,
|
|
", and limit of of %u",
|
|
limit);
|
|
dwarfstring_append(&m,
|
|
" something is very wrong. "
|
|
"a pairs pointer is null");
|
|
_dwarf_error_string(dbg,error,DW_DLE_DEBUG_NAMES_ERROR,
|
|
dwarfstring_string(&m));
|
|
dwarfstring_destructor(&m);
|
|
}
|
|
return DW_DLV_OK;
|
|
|
|
}
|
|
|
|
/* Each Name Table entry, one at a time.
|
|
It is not an error if array_size is zero or
|
|
small. Check the returned attr_count to
|
|
know now much of array filled in and
|
|
if the array you provided is
|
|
large enough. Possibly 40 is
|
|
sufficient.
|
|
name indexes start at 1. */
|
|
int
|
|
dwarf_dnames_name(Dwarf_Dnames_Head dn,
|
|
Dwarf_Unsigned name_index,
|
|
Dwarf_Unsigned * bucket_number,
|
|
Dwarf_Unsigned * hash_value,
|
|
Dwarf_Unsigned * offset_to_debug_str,
|
|
char * * ptrtostr ,
|
|
Dwarf_Unsigned * offset_in_entrypool,
|
|
Dwarf_Unsigned * abbrev_code,
|
|
Dwarf_Half * abbrev_tag,
|
|
Dwarf_Unsigned array_size,
|
|
Dwarf_Half * idxattr_array,
|
|
Dwarf_Half * form_array,
|
|
Dwarf_Unsigned * attr_count,
|
|
Dwarf_Error * error)
|
|
{
|
|
Dwarf_Debug dbg = 0;
|
|
int res = 0;
|
|
Dwarf_Unsigned entrypooloffset = 0;
|
|
Dwarf_Unsigned debugstroffset = 0;
|
|
Dwarf_Small * strpointer = 0;
|
|
struct Dwarf_D_Abbrev_s *abbrevdata = 0;
|
|
Dwarf_Unsigned code = 0;
|
|
|
|
if (!dn || dn->dn_magic != DWARF_DNAMES_MAGIC) {
|
|
_dwarf_error_string(NULL, error,DW_DLE_DBG_NULL,
|
|
"DW_DLE_DBG_NULL: "
|
|
"a call to dwarf_dnames_name() "
|
|
"Passes in a NULL or uninitialized pointer");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
dbg = dn->dn_dbg;
|
|
if (!dbg) {
|
|
_dwarf_error_string(NULL, error,DW_DLE_DBG_NULL,
|
|
"DW_DLE_DBG_NULL: "
|
|
"a call to dwarf_dnames_name() "
|
|
"finds a NULL Dwarf_Debug in a Dwarf_Dnames_Head");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (!name_index || name_index > dn->dn_name_count) {
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
res = get_bucket_number(dn,name_index,bucket_number);
|
|
if (res == DW_DLV_OK) {
|
|
res = get_hash_value_number(dn,name_index,hash_value,error);
|
|
if (res == DW_DLV_ERROR) {
|
|
return res;
|
|
}
|
|
}
|
|
{
|
|
Dwarf_Small *ptr = dn->dn_string_offsets +
|
|
(name_index-1) * dn->dn_offset_size;
|
|
Dwarf_Small *endptr = dn->dn_abbrevs;
|
|
|
|
READ_UNALIGNED_CK(dbg, debugstroffset, Dwarf_Unsigned,
|
|
ptr, dn->dn_offset_size,
|
|
error,endptr);
|
|
if (offset_to_debug_str) {
|
|
*offset_to_debug_str = debugstroffset;
|
|
}
|
|
}
|
|
/* Get str ptr from .debug_str */
|
|
{
|
|
Dwarf_Small *secdataptr = 0;
|
|
Dwarf_Unsigned secdatalen = 0;
|
|
Dwarf_Small *secend = 0;
|
|
int res_s = 0;
|
|
|
|
secdataptr = (Dwarf_Small *)dbg->de_debug_str.dss_data;
|
|
secdatalen = dbg->de_debug_str.dss_size;
|
|
secend = secdataptr+secdatalen;
|
|
strpointer = secdataptr +debugstroffset;
|
|
res_s = _dwarf_check_string_valid(dbg,
|
|
secdataptr,strpointer,secend,
|
|
DW_DLE_FORM_STRING_BAD_STRING,error);
|
|
if (res_s != DW_DLV_OK) {
|
|
return res_s;
|
|
}
|
|
if (ptrtostr) {
|
|
*ptrtostr = (char *)strpointer;
|
|
}
|
|
}
|
|
|
|
{
|
|
Dwarf_Small *ptr = dn->dn_entry_offsets +
|
|
(name_index-1) * dn->dn_offset_size;
|
|
Dwarf_Small *endptr = dn->dn_abbrevs;
|
|
/* offsets relative to the start of the
|
|
entry_pool */
|
|
|
|
READ_UNALIGNED_CK(dbg, entrypooloffset, Dwarf_Unsigned,
|
|
ptr, dn->dn_offset_size,
|
|
error,endptr);
|
|
if (entrypooloffset >= dn->dn_entry_pool_size) {
|
|
_dwarf_error_string(dbg, error,DW_DLE_DEBUG_NAMES_ERROR,
|
|
"DW_DLE_DEBUG_NAMES_ERROR: "
|
|
"The entrypool offset read is larger than"
|
|
"the entrypool size");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (offset_in_entrypool) {
|
|
*offset_in_entrypool = entrypooloffset;
|
|
}
|
|
}
|
|
/* Find abbrev code at the given entry offset */
|
|
res = _dwarf_read_abbrev_code_from_pool(dn,
|
|
entrypooloffset, &code,error);
|
|
if (res != DW_DLV_OK) {
|
|
return res;
|
|
}
|
|
res = _dwarf_find_abbrev_for_code(dn,code,&abbrevdata,error);
|
|
if (res == DW_DLV_ERROR) {
|
|
return res;
|
|
}
|
|
if (res == DW_DLV_NO_ENTRY) {
|
|
return res;
|
|
}
|
|
|
|
if (abbrev_code) {
|
|
*abbrev_code = code;
|
|
}
|
|
if (code && abbrev_tag) {
|
|
*abbrev_tag = (Dwarf_Half)abbrevdata->da_tag;
|
|
}
|
|
if (code) {
|
|
if (attr_count) {
|
|
*attr_count = abbrevdata->da_pairs_count;
|
|
}
|
|
res = _dwarf_fill_in_attr_form(dn,abbrevdata,idxattr_array,
|
|
form_array, array_size,error);
|
|
if (res == DW_DLV_ERROR) {
|
|
return res;
|
|
}
|
|
}
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
/* If abbrev_code returned is zero there is no tag returned
|
|
and we are at the end of the entry pool set for this name
|
|
entry.
|
|
abbrev code, tag
|
|
attr,form
|
|
...
|
|
0,0
|
|
... repeat like the above
|
|
0
|
|
*/
|
|
|
|
static int
|
|
_dwarf_internal_abbrev_by_code(Dwarf_Dnames_Head dn,
|
|
Dwarf_Unsigned abbrev_code,
|
|
Dwarf_Half *tag,
|
|
Dwarf_Unsigned *index_of_abbrev,
|
|
Dwarf_Unsigned *number_of_attr_form_entries)
|
|
{
|
|
Dwarf_Unsigned n = 0;
|
|
struct Dwarf_D_Abbrev_s * abbrev = 0;
|
|
|
|
abbrev = dn->dn_abbrev_instances;
|
|
for (n = 0; n < dn->dn_abbrev_instance_count; ++n,++abbrev) {
|
|
if (abbrev_code == abbrev->da_abbrev_code) {
|
|
if (tag) {
|
|
*tag = (Dwarf_Half)abbrev->da_tag;
|
|
}
|
|
if (index_of_abbrev) {
|
|
*index_of_abbrev = n;
|
|
}
|
|
if (number_of_attr_form_entries) {
|
|
*number_of_attr_form_entries = abbrev->da_pairs_count;
|
|
}
|
|
return DW_DLV_OK;
|
|
}
|
|
}
|
|
/* Something is wrong, not found! */
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
|
|
/* This, combined with dwarf_dnames_entrypool_values(),
|
|
lets one examine as much or as little of an entrypool
|
|
as one wants to by alternately calling these two
|
|
functions.
|
|
*/
|
|
|
|
int dwarf_dnames_entrypool(Dwarf_Dnames_Head dn,
|
|
Dwarf_Unsigned offset_in_entrypool,
|
|
Dwarf_Unsigned *abbrev_code,
|
|
Dwarf_Half *tag,
|
|
Dwarf_Unsigned *value_count,
|
|
Dwarf_Unsigned *index_of_abbrev,
|
|
Dwarf_Unsigned *offset_of_initial_value,
|
|
Dwarf_Error *error)
|
|
{
|
|
Dwarf_Debug dbg = 0;
|
|
int res = 0;
|
|
Dwarf_Small *entrypool = 0;
|
|
Dwarf_Small *endentrypool = 0;
|
|
Dwarf_Unsigned abcode = 0;
|
|
Dwarf_Unsigned leblen = 0;
|
|
if (!dn || dn->dn_magic != DWARF_DNAMES_MAGIC) {
|
|
_dwarf_error(NULL, error,DW_DLE_DBG_NULL);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
|
|
dbg = dn->dn_dbg;
|
|
if (offset_in_entrypool >= dn->dn_entry_pool_size) {
|
|
_dwarf_error(NULL, error,DW_DLE_DEBUG_NAMES_ENTRYPOOL_OFFSET);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
endentrypool = dn->dn_entry_pool +dn->dn_entry_pool_size;
|
|
entrypool = dn->dn_entry_pool + offset_in_entrypool;
|
|
|
|
DECODE_LEB128_UWORD_LEN_CK(entrypool,abcode,leblen,
|
|
dbg,error,endentrypool);
|
|
|
|
res = _dwarf_internal_abbrev_by_code(dn,
|
|
abcode,
|
|
tag, index_of_abbrev,
|
|
value_count);
|
|
if (res != DW_DLV_OK) {
|
|
/* Never DW_DLV_ERROR (so far) */
|
|
return res;
|
|
}
|
|
*offset_of_initial_value = offset_in_entrypool + leblen;
|
|
*abbrev_code = abcode;
|
|
return DW_DLV_OK;
|
|
}
|
|
|
|
static int
|
|
isformrefval(Dwarf_Debug dbg,Dwarf_Half form,
|
|
Dwarf_Small *poolptr,
|
|
Dwarf_Small *endpool,
|
|
Dwarf_Unsigned *val,
|
|
Dwarf_Unsigned *bytesread,
|
|
Dwarf_Error *error)
|
|
{
|
|
Dwarf_Unsigned localval =0;
|
|
|
|
switch(form) {
|
|
case DW_FORM_ref1:
|
|
*val = *poolptr;
|
|
*bytesread = 1;
|
|
break;
|
|
case DW_FORM_ref2:
|
|
READ_UNALIGNED_CK(dbg, localval, Dwarf_Unsigned,
|
|
poolptr, DWARF_HALF_SIZE,
|
|
error,endpool);
|
|
*bytesread = DWARF_HALF_SIZE;
|
|
*val = localval;
|
|
break;
|
|
case DW_FORM_ref4:
|
|
READ_UNALIGNED_CK(dbg, localval, Dwarf_Unsigned,
|
|
poolptr, DWARF_32BIT_SIZE,
|
|
error,endpool);
|
|
*bytesread = DWARF_32BIT_SIZE;
|
|
*val = localval;
|
|
break;
|
|
case DW_FORM_ref8:
|
|
default:
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
return DW_DLV_OK;
|
|
}
|
|
/* Caller, knowing array size needed, passes in arrays
|
|
it allocates of for idx, form, offset-size-values,
|
|
and signature values. Caller must examine idx-number
|
|
and form to decide, for each array element, whether
|
|
the offset or the signature contains the value.
|
|
So this returns all the values for the abbrev code.
|
|
And points via offset_of_next to the next abbrev code.
|
|
|
|
While an array of structs would be easier for the caller
|
|
to allocate than parallel arrays, public structs have
|
|
turned out to be difficult to work with as interfaces
|
|
(as formats change over time).
|
|
*/
|
|
int dwarf_dnames_entrypool_values(Dwarf_Dnames_Head dn,
|
|
Dwarf_Unsigned index_of_abbrev,
|
|
Dwarf_Unsigned offset_in_entrypool_of_values,
|
|
Dwarf_Unsigned array_sizes,
|
|
Dwarf_Half * array_dw_idx_number,
|
|
Dwarf_Half * array_form,
|
|
Dwarf_Unsigned * array_of_offsets,
|
|
Dwarf_Sig8 * array_of_signatures,
|
|
Dwarf_Bool * single_cu,
|
|
Dwarf_Unsigned * single_cu_offset,
|
|
/* offset of the next entrypool entry. */
|
|
Dwarf_Unsigned * offset_of_next_entrypool,
|
|
Dwarf_Error * error)
|
|
{
|
|
struct Dwarf_D_Abbrev_s * abbrev = 0;
|
|
Dwarf_Debug dbg = 0;
|
|
unsigned n = 0;
|
|
int res = 0;
|
|
Dwarf_Unsigned abcount = 0;
|
|
Dwarf_Unsigned pooloffset =
|
|
offset_in_entrypool_of_values;
|
|
Dwarf_Small * endpool = 0;
|
|
Dwarf_Small * poolptr = 0;
|
|
Dwarf_Unsigned bytesread = 0;
|
|
|
|
if (!dn || dn->dn_magic != DWARF_DNAMES_MAGIC) {
|
|
_dwarf_error_string(NULL, error,DW_DLE_DBG_NULL,
|
|
"DW_DLE_DBG_NULL: bad Head argument to "
|
|
"dwarf_dnames_entrypool_values");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
dbg = dn->dn_dbg;
|
|
endpool = dn->dn_entry_pool + dn->dn_entry_pool_size;
|
|
if (pooloffset >= dn->dn_entry_pool_size) {
|
|
/* make error or harmless error? */
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
if (index_of_abbrev >= dn->dn_abbrev_instance_count) {
|
|
/* make error or harmless error? */
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
|
|
poolptr = dn->dn_entry_pool + pooloffset;
|
|
abbrev = dn->dn_abbrev_instances + index_of_abbrev;
|
|
abcount = abbrev->da_pairs_count;
|
|
if (!abcount) {
|
|
return DW_DLV_NO_ENTRY;
|
|
}
|
|
if (abcount > array_sizes) {
|
|
dwarfstring m;
|
|
|
|
dwarfstring_constructor(&m);
|
|
dwarfstring_append_printf_u(&m,
|
|
"DW_DLE_DEBUG_NAMES_OFF_END: "
|
|
"The size of the pair of arrays "
|
|
"passed to dwarf_dnames_entrypool_values "
|
|
"is %u",
|
|
array_sizes);
|
|
dwarfstring_append_printf_u(&m,
|
|
" but the entry requires %u entries.",
|
|
abcount);
|
|
_dwarf_error_string(dbg,error,
|
|
DW_DLE_DEBUG_NAMES_OFF_END,
|
|
dwarfstring_string(&m));
|
|
dwarfstring_destructor(&m);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if (abcount > dn->dn_entry_pool_size) {
|
|
/* Just looking for a horrible giant value */
|
|
dwarfstring m;
|
|
|
|
dwarfstring_constructor(&m);
|
|
dwarfstring_append_printf_u(&m,
|
|
"DW_DLE_DEBUG_NAMES_ABBREV_CORRUPTION: "
|
|
"The abbrev count for this entry pool entry"
|
|
" is %u, impossibly large. Corrupt data",
|
|
abcount);
|
|
_dwarf_error_string(dbg,error,
|
|
DW_DLE_DEBUG_NAMES_ABBREV_CORRUPTION,
|
|
dwarfstring_string(&m));
|
|
dwarfstring_destructor(&m);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
for (n = 0; n < abcount ; ++n) {
|
|
Dwarf_Half idxtype = 0;
|
|
Dwarf_Half form = 0;
|
|
|
|
idxtype = abbrev->da_idxattr[n];
|
|
form = abbrev->da_form[n];
|
|
array_dw_idx_number[n] = idxtype;
|
|
array_form[n] = form;
|
|
|
|
if (!idxtype && !form) {
|
|
break;
|
|
}
|
|
|
|
if (form == DW_FORM_data8 && idxtype == DW_IDX_type_hash) {
|
|
if ((poolptr + sizeof(Dwarf_Sig8)) > endpool){
|
|
_dwarf_error(dbg,error,
|
|
DW_DLE_DEBUG_NAMES_ENTRYPOOL_OFFSET);
|
|
return DW_DLV_ERROR;
|
|
}
|
|
bytesread = sizeof(Dwarf_Sig8);
|
|
memcpy(array_of_signatures+n,
|
|
poolptr,bytesread);
|
|
poolptr += bytesread;
|
|
pooloffset += bytesread;
|
|
continue;
|
|
} else if (_dwarf_allow_formudata(form)) {
|
|
Dwarf_Unsigned val = 0;
|
|
res = _dwarf_formudata_internal(dbg,0,form,poolptr,
|
|
endpool,&val,&bytesread,error);
|
|
if (res != DW_DLV_OK) {
|
|
return res;
|
|
}
|
|
poolptr += bytesread;
|
|
pooloffset += bytesread;
|
|
|
|
array_of_offsets[n] = val;
|
|
continue;
|
|
} else {
|
|
Dwarf_Unsigned val = 0;
|
|
res =isformrefval(dbg,form,poolptr,
|
|
endpool,&val,&bytesread,error);
|
|
if (res == DW_DLV_ERROR) {
|
|
return res;
|
|
}
|
|
if (res == DW_DLV_OK) {
|
|
poolptr += bytesread;
|
|
if (poolptr > endpool) {
|
|
_dwarf_error_string(dbg,error,
|
|
DW_DLE_DEBUG_NAMES_ENTRYPOOL_OFFSET,
|
|
"DW_DLE_DEBUG_NAMES_ENTRYPOOL_OFFSET:"
|
|
" a DW_FORM_ref* would read past end"
|
|
" of the entrypool");
|
|
return DW_DLV_ERROR;
|
|
}
|
|
poolptr += bytesread;
|
|
pooloffset += bytesread;
|
|
array_of_offsets[n] = val;
|
|
continue;
|
|
}
|
|
}
|
|
/* There is some mistake/omission in our code here or in
|
|
the data. */
|
|
{
|
|
dwarfstring m;
|
|
const char *name = "<unexpected form>";
|
|
|
|
dwarfstring_constructor(&m);
|
|
dwarfstring_append_printf_u(&m,
|
|
"DW_DLE_DEBUG_NAMES_UNHANDLED_FORM: Form 0x%x",
|
|
form);
|
|
dwarf_get_FORM_name(form,&name);
|
|
dwarfstring_append_printf_s(&m,
|
|
" %s is not currently supported for .debug_names ",
|
|
(char *)name);
|
|
_dwarf_error_string(dbg,error,
|
|
DW_DLE_DEBUG_NAMES_UNHANDLED_FORM,
|
|
dwarfstring_string(&m));
|
|
dwarfstring_destructor(&m);
|
|
}
|
|
return DW_DLV_ERROR;
|
|
}
|
|
if ( dn->dn_single_cu) {
|
|
if (single_cu && single_cu_offset) {
|
|
*single_cu = dn->dn_single_cu;
|
|
*single_cu_offset = dn->dn_single_cu_offset;
|
|
}
|
|
}
|
|
*offset_of_next_entrypool = pooloffset;
|
|
return DW_DLV_OK;
|
|
}
|