Fix the decoding of DW_FORM_ref_addr DWARF attribute.

* dwarf.c (struct abbrev_list): New structure.  Used to collect
	lists of abbreviation sets.
	(struct abbrev_map): New structure.  Used to map CU offsets to
	abbreviation offsets.
	(record_abbrev_list): New function.  A new entry to an
	abbreviation list.
	(free_all_abbrevs): Update to free abbreviation lists.
	(new_abbrev_list): New function.  Start a new abbreviation
	list.
	(find_abbrev_list_by_abbrev_offset): New function.
	(find_abbrev_map_by_offset): New function.
	(add_abbrev): Add abbrev_list parameter.
	(add_abbrev_attr): Likewise.
	(process_abbrev_section): Rename to process_abbrev_set and add
	list parameter.
	(get_type_abbrev_from_form): New function.  Attempts to decode the
	forms used by DW_AT_type attributes.
	(get_type_signedness): Display type names if operating in wide
	mode.  Use get_type_abbrev_from_form.
	(read_and_display_attr_value): Use get_type_abbrev_from_form.
	(process_debug_info): Pre-parse the CU headers to collate all the
	abbrevs before starting the main scan.
	(process_debug_abbrev): Do not free any loaded abbrevs.
	(free_debug_memory): Free the abbrev maps.
This commit is contained in:
Nick Clifton
2020-10-27 16:17:13 +00:00
parent 7f40ce1a9e
commit bcd213b2cf
2 changed files with 482 additions and 146 deletions

View File

@ -1,3 +1,30 @@
2020-10-27 Nick Clifton <nickc@redhat.com>
* dwarf.c (struct abbrev_list): New structure. Used to collect
lists of abbreviation sets.
(struct abbrev_map): New structure. Used to map CU offsets to
abbreviation offsets.
(record_abbrev_list): New function. A new entry to an
abbreviation list.
(free_all_abbrevs): Update to free abbreviation lists.
(new_abbrev_list): New function. Start a new abbreviation
list.
(find_abbrev_list_by_abbrev_offset): New function.
(find_abbrev_map_by_offset): New function.
(add_abbrev): Add abbrev_list parameter.
(add_abbrev_attr): Likewise.
(process_abbrev_section): Rename to process_abbrev_set and add
list parameter.
(get_type_abbrev_from_form): New function. Attempts to decode the
forms used by DW_AT_type attributes.
(get_type_signedness): Display type names if operating in wide
mode. Use get_type_abbrev_from_form.
(read_and_display_attr_value): Use get_type_abbrev_from_form.
(process_debug_info): Pre-parse the CU headers to collate all the
abbrevs before starting the main scan.
(process_debug_abbrev): Do not free any loaded abbrevs.
(free_debug_memory): Free the abbrev maps.
2020-10-22 H.J. Lu <hongjiu.lu@intel.com> 2020-10-22 H.J. Lu <hongjiu.lu@intel.com>
* testsuite/binutils-all/objcopy.exp (objcopy_test): Report * testsuite/binutils-all/objcopy.exp (objcopy_test): Report

View File

@ -849,6 +849,7 @@ fetch_indexed_value (dwarf_vma offset, dwarf_vma bytes)
/* FIXME: There are better and more efficient ways to handle /* FIXME: There are better and more efficient ways to handle
these structures. For now though, I just want something that these structures. For now though, I just want something that
is simple to implement. */ is simple to implement. */
/* Records a single attribute in an abbrev. */
typedef struct abbrev_attr typedef struct abbrev_attr
{ {
unsigned long attribute; unsigned long attribute;
@ -858,9 +859,10 @@ typedef struct abbrev_attr
} }
abbrev_attr; abbrev_attr;
/* Records a single abbrev. */
typedef struct abbrev_entry typedef struct abbrev_entry
{ {
unsigned long entry; unsigned long number;
unsigned long tag; unsigned long tag;
int children; int children;
struct abbrev_attr * first_attr; struct abbrev_attr * first_attr;
@ -869,15 +871,66 @@ typedef struct abbrev_entry
} }
abbrev_entry; abbrev_entry;
static abbrev_entry *first_abbrev = NULL; /* Records a set of abbreviations. */
static abbrev_entry *last_abbrev = NULL; typedef struct abbrev_list
{
abbrev_entry * first_abbrev;
abbrev_entry * last_abbrev;
dwarf_vma abbrev_offset;
struct abbrev_list * next;
unsigned char * start_of_next_abbrevs;
}
abbrev_list;
/* Records all the abbrevs found so far. */
static struct abbrev_list * abbrev_lists = NULL;
typedef struct abbrev_map
{
dwarf_vma start;
dwarf_vma end;
abbrev_list * list;
} abbrev_map;
/* Maps between CU offsets and abbrev sets. */
static abbrev_map * cu_abbrev_map = NULL;
static unsigned long num_abbrev_map_entries = 0;
static unsigned long next_free_abbrev_map_entry = 0;
#define INITIAL_NUM_ABBREV_MAP_ENTRIES 8
#define ABBREV_MAP_ENTRIES_INCREMENT 8
static void static void
free_abbrevs (void) record_abbrev_list_for_cu (dwarf_vma start, dwarf_vma end, abbrev_list * list)
{ {
if (cu_abbrev_map == NULL)
{
num_abbrev_map_entries = INITIAL_NUM_ABBREV_MAP_ENTRIES;
cu_abbrev_map = xmalloc (num_abbrev_map_entries * sizeof (* cu_abbrev_map));
}
else if (next_free_abbrev_map_entry == num_abbrev_map_entries)
{
num_abbrev_map_entries += ABBREV_MAP_ENTRIES_INCREMENT;
cu_abbrev_map = xrealloc (cu_abbrev_map, num_abbrev_map_entries * sizeof (* cu_abbrev_map));
}
cu_abbrev_map[next_free_abbrev_map_entry].start = start;
cu_abbrev_map[next_free_abbrev_map_entry].end = end;
cu_abbrev_map[next_free_abbrev_map_entry].list = list;
next_free_abbrev_map_entry ++;
}
static void
free_all_abbrevs (void)
{
abbrev_list * list;
for (list = abbrev_lists; list != NULL;)
{
abbrev_list * next = list->next;
abbrev_entry * abbrv; abbrev_entry * abbrv;
for (abbrv = first_abbrev; abbrv;) for (abbrv = list->first_abbrev; abbrv != NULL;)
{ {
abbrev_entry * next_abbrev = abbrv->next; abbrev_entry * next_abbrev = abbrv->next;
abbrev_attr * attr; abbrev_attr * attr;
@ -894,56 +947,106 @@ free_abbrevs (void)
abbrv = next_abbrev; abbrv = next_abbrev;
} }
last_abbrev = first_abbrev = NULL; free (list);
list = next;
}
abbrev_lists = NULL;
}
static abbrev_list *
new_abbrev_list (dwarf_vma abbrev_offset)
{
abbrev_list * list = (abbrev_list *) xcalloc (sizeof * list, 1);
list->abbrev_offset = abbrev_offset;
list->next = abbrev_lists;
abbrev_lists = list;
return list;
}
static abbrev_list *
find_abbrev_list_by_abbrev_offset (dwarf_vma abbrev_offset)
{
abbrev_list * list;
for (list = abbrev_lists; list != NULL; list = list->next)
if (list->abbrev_offset == abbrev_offset)
return list;
return NULL;
}
/* Find the abbreviation map for the CU that includes OFFSET.
OFFSET is an absolute offset from the start of the .debug_info section. */
/* FIXME: This function is going to slow down readelf & objdump.
Consider using a better algorithm to mitigate this effect. */
static abbrev_map *
find_abbrev_map_by_offset (dwarf_vma offset)
{
unsigned long i;
for (i = 0; i < next_free_abbrev_map_entry; i++)
if (cu_abbrev_map[i].start <= offset
&& cu_abbrev_map[i].end > offset)
return cu_abbrev_map + i;
return NULL;
} }
static void static void
add_abbrev (unsigned long number, unsigned long tag, int children) add_abbrev (unsigned long number,
unsigned long tag,
int children,
abbrev_list * list)
{ {
abbrev_entry * entry; abbrev_entry * entry;
entry = (abbrev_entry *) malloc (sizeof (*entry)); entry = (abbrev_entry *) xmalloc (sizeof (*entry));
if (entry == NULL)
/* ugg */
return;
entry->entry = number; entry->number = number;
entry->tag = tag; entry->tag = tag;
entry->children = children; entry->children = children;
entry->first_attr = NULL; entry->first_attr = NULL;
entry->last_attr = NULL; entry->last_attr = NULL;
entry->next = NULL; entry->next = NULL;
if (first_abbrev == NULL) assert (list != NULL);
first_abbrev = entry;
else
last_abbrev->next = entry;
last_abbrev = entry; if (list->first_abbrev == NULL)
list->first_abbrev = entry;
else
list->last_abbrev->next = entry;
list->last_abbrev = entry;
} }
static void static void
add_abbrev_attr (unsigned long attribute, unsigned long form, add_abbrev_attr (unsigned long attribute,
bfd_signed_vma implicit_const) unsigned long form,
bfd_signed_vma implicit_const,
abbrev_list * list)
{ {
abbrev_attr *attr; abbrev_attr *attr;
attr = (abbrev_attr *) malloc (sizeof (*attr)); attr = (abbrev_attr *) xmalloc (sizeof (*attr));
if (attr == NULL)
/* ugg */
return;
attr->attribute = attribute; attr->attribute = attribute;
attr->form = form; attr->form = form;
attr->implicit_const = implicit_const; attr->implicit_const = implicit_const;
attr->next = NULL; attr->next = NULL;
if (last_abbrev->first_attr == NULL) assert (list != NULL && list->last_abbrev != NULL);
last_abbrev->first_attr = attr;
else
last_abbrev->last_attr->next = attr;
last_abbrev->last_attr = attr; if (list->last_abbrev->first_attr == NULL)
list->last_abbrev->first_attr = attr;
else
list->last_abbrev->last_attr->next = attr;
list->last_abbrev->last_attr = attr;
} }
/* Processes the (partial) contents of a .debug_abbrev section. /* Processes the (partial) contents of a .debug_abbrev section.
@ -952,11 +1055,10 @@ add_abbrev_attr (unsigned long attribute, unsigned long form,
an abbreviation set was found. */ an abbreviation set was found. */
static unsigned char * static unsigned char *
process_abbrev_section (unsigned char *start, unsigned char *end) process_abbrev_set (unsigned char * start,
const unsigned char * end,
abbrev_list * list)
{ {
if (first_abbrev != NULL)
return NULL;
while (start < end) while (start < end)
{ {
unsigned long entry; unsigned long entry;
@ -966,7 +1068,7 @@ process_abbrev_section (unsigned char *start, unsigned char *end)
READ_ULEB (entry, start, end); READ_ULEB (entry, start, end);
/* A single zero is supposed to end the section according /* A single zero is supposed to end the set according
to the standard. If there's more, then signal that to to the standard. If there's more, then signal that to
the caller. */ the caller. */
if (start == end) if (start == end)
@ -980,7 +1082,7 @@ process_abbrev_section (unsigned char *start, unsigned char *end)
children = *start++; children = *start++;
add_abbrev (entry, tag, children); add_abbrev (entry, tag, children, list);
do do
{ {
@ -1003,7 +1105,7 @@ process_abbrev_section (unsigned char *start, unsigned char *end)
break; break;
} }
add_abbrev_attr (attribute, form, implicit_const); add_abbrev_attr (attribute, form, implicit_const, list);
} }
while (attribute != 0); while (attribute != 0);
} }
@ -1969,36 +2071,123 @@ skip_attr_bytes (unsigned long form,
return data; return data;
} }
/* Return IS_SIGNED set to TRUE if the type at /* Given form FORM with value UVALUE, locate and return the abbreviation
DATA can be determined to be a signed type. */ associated with it. */
static abbrev_entry *
get_type_abbrev_from_form (unsigned long form,
unsigned long uvalue,
dwarf_vma cu_offset,
const struct dwarf_section * section,
unsigned long * abbrev_num_return,
unsigned char ** data_return,
unsigned long * cu_offset_return)
{
unsigned long abbrev_number;
abbrev_map * map;
abbrev_entry * entry;
unsigned char * data;
if (abbrev_num_return != NULL)
* abbrev_num_return = 0;
if (data_return != NULL)
* data_return = NULL;
switch (form)
{
case DW_FORM_GNU_ref_alt:
/* FIXME: We are unable to handle this form at the moment. */
return NULL;
case DW_FORM_ref_addr:
if (uvalue >= section->size)
{
warn (_("Unable to resolve ref_addr form: uvalue %lx > section size %lx (%s)\n"),
uvalue, (long) section->size, section->name);
return NULL;
}
break;
case DW_FORM_ref1:
case DW_FORM_ref2:
case DW_FORM_ref4:
case DW_FORM_ref_udata:
if (uvalue + cu_offset > section->size)
{
warn (_("Unable to resolve ref form: uvalue %lx + cu_offset %lx > section size %lx\n"),
uvalue, (long) cu_offset, (long) section->size);
return NULL;
}
uvalue += cu_offset;
break;
/* FIXME: Are there other DW_FORMs that can be used by types ? */
default:
warn (_("Unexpected form %lx encountered whilst finding abbreviation for type\n"), form);
return NULL;
}
data = (unsigned char *) section->start + uvalue;
map = find_abbrev_map_by_offset (uvalue);
if (map == NULL)
{
warn (_("Unable to find abbreviations for CU offset %#lx\n"), uvalue);
return NULL;
}
if (map->list == NULL)
{
warn (_("Empty abbreviation list encountered for CU offset %lx\n"), uvalue);
return NULL;
}
if (cu_offset_return != NULL)
{
if (form == DW_FORM_ref_addr)
* cu_offset_return = map->start;
else
* cu_offset_return = cu_offset;
}
READ_ULEB (abbrev_number, data, section->start + section->size);
for (entry = map->list->first_abbrev; entry != NULL; entry = entry->next)
if (entry->number == abbrev_number)
break;
if (abbrev_num_return != NULL)
* abbrev_num_return = abbrev_number;
if (data_return != NULL)
* data_return = data;
if (entry == NULL)
warn (_("Unable to find entry for abbreviation %lu\n"), abbrev_number);
return entry;
}
/* Return IS_SIGNED set to TRUE if the type using abbreviation ENTRY
can be determined to be a signed type. The data for ENTRY can be
found starting at DATA. */
static void static void
get_type_signedness (unsigned char * start, get_type_signedness (abbrev_entry * entry,
const struct dwarf_section * section,
unsigned char * data, unsigned char * data,
unsigned const char * end, unsigned const char * end,
dwarf_vma cu_offset,
dwarf_vma pointer_size, dwarf_vma pointer_size,
dwarf_vma offset_size, dwarf_vma offset_size,
int dwarf_version, int dwarf_version,
bfd_boolean * is_signed, bfd_boolean * is_signed,
unsigned int nesting) unsigned int nesting)
{ {
unsigned long abbrev_number;
abbrev_entry * entry;
abbrev_attr * attr; abbrev_attr * attr;
* is_signed = FALSE; * is_signed = FALSE;
READ_ULEB (abbrev_number, data, end);
for (entry = first_abbrev;
entry != NULL && entry->entry != abbrev_number;
entry = entry->next)
continue;
if (entry == NULL)
/* FIXME: Issue a warning ? */
return;
#define MAX_NESTING 20 #define MAX_NESTING 20
if (nesting > MAX_NESTING) if (nesting > MAX_NESTING)
{ {
@ -2011,6 +2200,7 @@ get_type_signedness (unsigned char * start,
attr != NULL && attr->attribute; attr != NULL && attr->attribute;
attr = attr->next) attr = attr->next)
{ {
unsigned char * orig_data = data;
dwarf_vma uvalue = 0; dwarf_vma uvalue = 0;
data = skip_attr_bytes (attr->form, data, end, pointer_size, data = skip_attr_bytes (attr->form, data, end, pointer_size,
@ -2020,21 +2210,38 @@ get_type_signedness (unsigned char * start,
switch (attr->attribute) switch (attr->attribute)
{ {
#if 0 /* FIXME: It would be nice to print the name of the type, case DW_AT_linkage_name:
but this would mean updating a lot of binutils tests. */
case DW_AT_name: case DW_AT_name:
if (do_wide)
{
if (attr->form == DW_FORM_strp) if (attr->form == DW_FORM_strp)
printf ("%s", fetch_indirect_string (uvalue)); printf (", %s", fetch_indirect_string (uvalue));
else if (attr->form == DW_FORM_string)
printf (", %s", orig_data);
}
break; break;
#endif
case DW_AT_type: case DW_AT_type:
/* Recurse. */ /* Recurse. */
if (uvalue >= (size_t) (end - start)) {
return; abbrev_entry * type_abbrev;
/* We cannot correctly process DW_FORM_ref_addr at the moment. */ unsigned char * type_data;
if (attr->form != DW_FORM_ref_addr) unsigned long type_cu_offset;
get_type_signedness (start, start + uvalue, end, pointer_size,
offset_size, dwarf_version, is_signed, nesting + 1); type_abbrev = get_type_abbrev_from_form (attr->form,
uvalue,
cu_offset,
section,
NULL /* abbrev num return */,
& type_data,
& type_cu_offset);
if (type_abbrev == NULL)
break;
get_type_signedness (type_abbrev, section, type_data, end, type_cu_offset,
pointer_size, offset_size, dwarf_version,
is_signed, nesting + 1);
}
break; break;
case DW_AT_encoding: case DW_AT_encoding:
@ -2667,11 +2874,18 @@ read_and_display_attr_value (unsigned long attribute,
&& uvalue < (size_t) (end - start)) && uvalue < (size_t) (end - start))
{ {
bfd_boolean is_signed = FALSE; bfd_boolean is_signed = FALSE;
abbrev_entry * type_abbrev;
unsigned char * type_data;
unsigned long type_cu_offset;
/* We cannot correctly process DW_FORM_ref_addr at the moment. */ type_abbrev = get_type_abbrev_from_form (form, uvalue, cu_offset,
if (form != DW_FORM_ref_addr) section, NULL, & type_data, & type_cu_offset);
get_type_signedness (start, start + uvalue, end, pointer_size, if (type_abbrev != NULL)
offset_size, dwarf_version, & is_signed, 0); {
get_type_signedness (type_abbrev, section, type_data, end, type_cu_offset,
pointer_size, offset_size, dwarf_version,
& is_signed, 0);
}
level_type_signed[level] = is_signed; level_type_signed[level] = is_signed;
} }
break; break;
@ -2993,40 +3207,22 @@ read_and_display_attr_value (unsigned long attribute,
case DW_AT_import: case DW_AT_import:
{ {
if (form == DW_FORM_ref_sig8 unsigned long abbrev_number;
|| form == DW_FORM_GNU_ref_alt) abbrev_entry *entry;
break;
if (form == DW_FORM_ref1 entry = get_type_abbrev_from_form (form, uvalue, cu_offset,
|| form == DW_FORM_ref2 section, & abbrev_number, NULL, NULL);
|| form == DW_FORM_ref4 if (entry == NULL)
|| form == DW_FORM_ref_udata) {
uvalue += cu_offset; if (form != DW_FORM_GNU_ref_alt)
if (uvalue >= section->size)
warn (_("Offset %s used as value for DW_AT_import attribute of DIE at offset 0x%lx is too big.\n"), warn (_("Offset %s used as value for DW_AT_import attribute of DIE at offset 0x%lx is too big.\n"),
dwarf_vmatoa ("x", uvalue), dwarf_vmatoa ("x", uvalue),
(unsigned long) (orig_data - section->start)); (unsigned long) (orig_data - section->start));
}
else else
{ {
unsigned long abbrev_number;
abbrev_entry *entry;
unsigned char *p = section->start + uvalue;
READ_ULEB (abbrev_number, p, end);
printf (_("\t[Abbrev Number: %ld"), abbrev_number); printf (_("\t[Abbrev Number: %ld"), abbrev_number);
/* Don't look up abbrev for DW_FORM_ref_addr, as it very often will
use different abbrev table, and we don't track .debug_info chunks
yet. */
if (form != DW_FORM_ref_addr)
{
for (entry = first_abbrev; entry != NULL; entry = entry->next)
if (entry->entry == abbrev_number)
break;
if (entry != NULL)
printf (" (%s)", get_TAG_name (entry->tag)); printf (" (%s)", get_TAG_name (entry->tag));
}
printf ("]"); printf ("]");
} }
} }
@ -3246,7 +3442,97 @@ process_debug_info (struct dwarf_section * section,
if (!do_loc && dwarf_start_die == 0) if (!do_loc && dwarf_start_die == 0)
introduce (section, FALSE); introduce (section, FALSE);
for (section_begin = start, unit = 0; start < end; unit++) free_all_abbrevs ();
free (cu_abbrev_map);
cu_abbrev_map = NULL;
next_free_abbrev_map_entry = 0;
/* In order to be able to resolve DW_FORM_ref_attr forms we need
to load *all* of the abbrevs for all CUs in this .debug_info
section. This does effectively mean that we (partially) read
every CU header twice. */
for (section_begin = start; start < end;)
{
DWARF2_Internal_CompUnit compunit;
unsigned char * hdrptr;
dwarf_vma cu_offset;
unsigned int offset_size;
unsigned int initial_length_size;
struct cu_tu_set * this_set;
abbrev_list * list;
hdrptr = start;
SAFE_BYTE_GET_AND_INC (compunit.cu_length, hdrptr, 4, end);
if (compunit.cu_length == 0xffffffff)
{
SAFE_BYTE_GET_AND_INC (compunit.cu_length, hdrptr, 8, end);
offset_size = 8;
initial_length_size = 12;
}
else
{
offset_size = 4;
initial_length_size = 4;
}
SAFE_BYTE_GET_AND_INC (compunit.cu_version, hdrptr, 2, end);
cu_offset = start - section_begin;
this_set = find_cu_tu_set_v2 (cu_offset, do_types);
if (compunit.cu_version < 5)
{
compunit.cu_unit_type = DW_UT_compile;
/* Initialize it due to a false compiler warning. */
compunit.cu_pointer_size = -1;
}
else
{
SAFE_BYTE_GET_AND_INC (compunit.cu_unit_type, hdrptr, 1, end);
do_types = (compunit.cu_unit_type == DW_UT_type);
SAFE_BYTE_GET_AND_INC (compunit.cu_pointer_size, hdrptr, 1, end);
}
SAFE_BYTE_GET_AND_INC (compunit.cu_abbrev_offset, hdrptr, offset_size, end);
list = find_abbrev_list_by_abbrev_offset (compunit.cu_abbrev_offset);
if (list == NULL)
{
dwarf_vma abbrev_base;
size_t abbrev_size;
unsigned char * next;
if (this_set == NULL)
{
abbrev_base = 0;
abbrev_size = debug_displays [abbrev_sec].section.size;
}
else
{
abbrev_base = this_set->section_offsets [DW_SECT_ABBREV];
abbrev_size = this_set->section_sizes [DW_SECT_ABBREV];
}
list = new_abbrev_list (compunit.cu_abbrev_offset);
next = process_abbrev_set
(((unsigned char *) debug_displays [abbrev_sec].section.start
+ abbrev_base + compunit.cu_abbrev_offset),
((unsigned char *) debug_displays [abbrev_sec].section.start
+ abbrev_base + abbrev_size),
list);
list->start_of_next_abbrevs = next;
}
start = section_begin + cu_offset + compunit.cu_length
+ initial_length_size;
record_abbrev_list_for_cu (cu_offset, start - section_begin, list);
}
for (start = section_begin, unit = 0; start < end; unit++)
{ {
DWARF2_Internal_CompUnit compunit; DWARF2_Internal_CompUnit compunit;
unsigned char *hdrptr; unsigned char *hdrptr;
@ -3262,6 +3548,7 @@ process_debug_info (struct dwarf_section * section,
struct cu_tu_set *this_set; struct cu_tu_set *this_set;
dwarf_vma abbrev_base; dwarf_vma abbrev_base;
size_t abbrev_size; size_t abbrev_size;
abbrev_list * list = NULL;
hdrptr = start; hdrptr = start;
@ -3439,8 +3726,6 @@ process_debug_info (struct dwarf_section * section,
continue; continue;
} }
free_abbrevs ();
/* Process the abbrevs used by this compilation unit. */ /* Process the abbrevs used by this compilation unit. */
if (compunit.cu_abbrev_offset >= abbrev_size) if (compunit.cu_abbrev_offset >= abbrev_size)
warn (_("Debug info is corrupted, abbrev offset (%lx) is larger than abbrev section size (%lx)\n"), warn (_("Debug info is corrupted, abbrev offset (%lx) is larger than abbrev section size (%lx)\n"),
@ -3453,11 +3738,22 @@ process_debug_info (struct dwarf_section * section,
(unsigned long) abbrev_base + abbrev_size, (unsigned long) abbrev_base + abbrev_size,
(unsigned long) debug_displays [abbrev_sec].section.size); (unsigned long) debug_displays [abbrev_sec].section.size);
else else
process_abbrev_section {
list = find_abbrev_list_by_abbrev_offset (compunit.cu_abbrev_offset);
if (list == NULL)
{
unsigned char * next;
list = new_abbrev_list (compunit.cu_abbrev_offset);
next = process_abbrev_set
(((unsigned char *) debug_displays [abbrev_sec].section.start (((unsigned char *) debug_displays [abbrev_sec].section.start
+ abbrev_base + compunit.cu_abbrev_offset), + abbrev_base + compunit.cu_abbrev_offset),
((unsigned char *) debug_displays [abbrev_sec].section.start ((unsigned char *) debug_displays [abbrev_sec].section.start
+ abbrev_base + abbrev_size)); + abbrev_base + abbrev_size),
list);
list->start_of_next_abbrevs = next;
}
}
level = 0; level = 0;
last_level = level; last_level = level;
@ -3537,11 +3833,13 @@ process_debug_info (struct dwarf_section * section,
/* Scan through the abbreviation list until we reach the /* Scan through the abbreviation list until we reach the
correct entry. */ correct entry. */
for (entry = first_abbrev; if (list == NULL)
entry && entry->entry != abbrev_number;
entry = entry->next)
continue; continue;
for (entry = list->first_abbrev; entry != NULL; entry = entry->next)
if (entry->number == abbrev_number)
break;
if (entry == NULL) if (entry == NULL)
{ {
if (!do_loc && do_printing) if (!do_loc && do_printing)
@ -5763,30 +6061,37 @@ display_debug_abbrev (struct dwarf_section *section,
{ {
abbrev_entry *entry; abbrev_entry *entry;
unsigned char *start = section->start; unsigned char *start = section->start;
unsigned char *end = start + section->size; const unsigned char *end = start + section->size;
introduce (section, FALSE); introduce (section, FALSE);
do do
{ {
unsigned char *last; abbrev_list * list;
dwarf_vma offset;
free_abbrevs (); offset = start - section->start;
list = find_abbrev_list_by_abbrev_offset (offset);
if (list == NULL)
{
list = new_abbrev_list (offset);
start = process_abbrev_set (start, end, list);
list->start_of_next_abbrevs = start;
}
else
start = list->start_of_next_abbrevs;
last = start; if (list->first_abbrev == NULL)
start = process_abbrev_section (start, end);
if (first_abbrev == NULL)
continue; continue;
printf (_(" Number TAG (0x%lx)\n"), (long) (last - section->start)); printf (_(" Number TAG (0x%lx)\n"), (long) offset);
for (entry = first_abbrev; entry; entry = entry->next) for (entry = list->first_abbrev; entry; entry = entry->next)
{ {
abbrev_attr *attr; abbrev_attr *attr;
printf (" %ld %s [%s]\n", printf (" %ld %s [%s]\n",
entry->entry, entry->number,
get_TAG_name (entry->tag), get_TAG_name (entry->tag),
entry->children ? _("has children") : _("no children")); entry->children ? _("has children") : _("no children"));
@ -10828,7 +11133,11 @@ free_debug_memory (void)
{ {
unsigned int i; unsigned int i;
free_abbrevs (); free_all_abbrevs ();
free (cu_abbrev_map);
cu_abbrev_map = NULL;
next_free_abbrev_map_entry = 0;
for (i = 0; i < max; i++) for (i = 0; i < max; i++)
free_debug_section ((enum dwarf_section_display_enum) i); free_debug_section ((enum dwarf_section_display_enum) i);