From: Nick Clifton Date: Tue, 27 Oct 2020 16:17:13 +0000 (+0000) Subject: Fix the decoding of DW_FORM_ref_addr DWARF attribute. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=bcd213b2cfbca2df53fb7e5d187fd67ea8eb7185;p=binutils-gdb.git 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. --- diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 4c14fd15103..0aa511dacad 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,30 @@ +2020-10-27 Nick Clifton + + * 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 * testsuite/binutils-all/objcopy.exp (objcopy_test): Report diff --git a/binutils/dwarf.c b/binutils/dwarf.c index c842aba6c1e..5cfa528594f 100644 --- a/binutils/dwarf.c +++ b/binutils/dwarf.c @@ -849,101 +849,204 @@ fetch_indexed_value (dwarf_vma offset, dwarf_vma bytes) /* FIXME: There are better and more efficient ways to handle these structures. For now though, I just want something that is simple to implement. */ +/* Records a single attribute in an abbrev. */ typedef struct abbrev_attr { - unsigned long attribute; - unsigned long form; - bfd_signed_vma implicit_const; - struct abbrev_attr *next; + unsigned long attribute; + unsigned long form; + bfd_signed_vma implicit_const; + struct abbrev_attr * next; } abbrev_attr; +/* Records a single abbrev. */ typedef struct abbrev_entry { - unsigned long entry; - unsigned long tag; - int children; - struct abbrev_attr *first_attr; - struct abbrev_attr *last_attr; - struct abbrev_entry *next; + unsigned long number; + unsigned long tag; + int children; + struct abbrev_attr * first_attr; + struct abbrev_attr * last_attr; + struct abbrev_entry * next; } abbrev_entry; -static abbrev_entry *first_abbrev = NULL; -static abbrev_entry *last_abbrev = NULL; +/* Records a set of abbreviations. */ +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 +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_abbrevs (void) +free_all_abbrevs (void) { - abbrev_entry *abbrv; + abbrev_list * list; - for (abbrv = first_abbrev; abbrv;) + for (list = abbrev_lists; list != NULL;) { - abbrev_entry *next_abbrev = abbrv->next; - abbrev_attr *attr; + abbrev_list * next = list->next; + abbrev_entry * abbrv; - for (attr = abbrv->first_attr; attr;) + for (abbrv = list->first_abbrev; abbrv != NULL;) { - abbrev_attr *next_attr = attr->next; + abbrev_entry * next_abbrev = abbrv->next; + abbrev_attr * attr; + + for (attr = abbrv->first_attr; attr;) + { + abbrev_attr *next_attr = attr->next; - free (attr); - attr = next_attr; + free (attr); + attr = next_attr; + } + + free (abbrv); + abbrv = next_abbrev; } - free (abbrv); - abbrv = next_abbrev; + free (list); + list = next; } - last_abbrev = first_abbrev = NULL; + 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 -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)); - if (entry == NULL) - /* ugg */ - return; + entry = (abbrev_entry *) xmalloc (sizeof (*entry)); - entry->entry = number; + entry->number = number; entry->tag = tag; entry->children = children; entry->first_attr = NULL; entry->last_attr = NULL; entry->next = NULL; - if (first_abbrev == NULL) - first_abbrev = entry; + assert (list != NULL); + + if (list->first_abbrev == NULL) + list->first_abbrev = entry; else - last_abbrev->next = entry; + list->last_abbrev->next = entry; - last_abbrev = entry; + list->last_abbrev = entry; } static void -add_abbrev_attr (unsigned long attribute, unsigned long form, - bfd_signed_vma implicit_const) +add_abbrev_attr (unsigned long attribute, + unsigned long form, + bfd_signed_vma implicit_const, + abbrev_list * list) { abbrev_attr *attr; - attr = (abbrev_attr *) malloc (sizeof (*attr)); - if (attr == NULL) - /* ugg */ - return; + attr = (abbrev_attr *) xmalloc (sizeof (*attr)); attr->attribute = attribute; attr->form = form; attr->implicit_const = implicit_const; attr->next = NULL; - if (last_abbrev->first_attr == NULL) - last_abbrev->first_attr = attr; + assert (list != NULL && list->last_abbrev != NULL); + + if (list->last_abbrev->first_attr == NULL) + list->last_abbrev->first_attr = attr; else - last_abbrev->last_attr->next = attr; + list->last_abbrev->last_attr->next = attr; - last_abbrev->last_attr = attr; + list->last_abbrev->last_attr = attr; } /* 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. */ 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) { unsigned long entry; @@ -966,7 +1068,7 @@ process_abbrev_section (unsigned char *start, unsigned char *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 the caller. */ if (start == end) @@ -980,7 +1082,7 @@ process_abbrev_section (unsigned char *start, unsigned char *end) children = *start++; - add_abbrev (entry, tag, children); + add_abbrev (entry, tag, children, list); do { @@ -1003,7 +1105,7 @@ process_abbrev_section (unsigned char *start, unsigned char *end) break; } - add_abbrev_attr (attribute, form, implicit_const); + add_abbrev_attr (attribute, form, implicit_const, list); } while (attribute != 0); } @@ -1969,36 +2071,123 @@ skip_attr_bytes (unsigned long form, return data; } -/* Return IS_SIGNED set to TRUE if the type at - DATA can be determined to be a signed type. */ +/* Given form FORM with value UVALUE, locate and return the abbreviation + 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 -get_type_signedness (unsigned char * start, +get_type_signedness (abbrev_entry * entry, + const struct dwarf_section * section, unsigned char * data, unsigned const char * end, + dwarf_vma cu_offset, dwarf_vma pointer_size, dwarf_vma offset_size, int dwarf_version, bfd_boolean * is_signed, unsigned int nesting) { - unsigned long abbrev_number; - abbrev_entry * entry; abbrev_attr * attr; * 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 if (nesting > MAX_NESTING) { @@ -2011,6 +2200,7 @@ get_type_signedness (unsigned char * start, attr != NULL && attr->attribute; attr = attr->next) { + unsigned char * orig_data = data; dwarf_vma uvalue = 0; data = skip_attr_bytes (attr->form, data, end, pointer_size, @@ -2020,21 +2210,38 @@ get_type_signedness (unsigned char * start, switch (attr->attribute) { -#if 0 /* FIXME: It would be nice to print the name of the type, - but this would mean updating a lot of binutils tests. */ + case DW_AT_linkage_name: case DW_AT_name: - if (attr->form == DW_FORM_strp) - printf ("%s", fetch_indirect_string (uvalue)); + if (do_wide) + { + if (attr->form == DW_FORM_strp) + printf (", %s", fetch_indirect_string (uvalue)); + else if (attr->form == DW_FORM_string) + printf (", %s", orig_data); + } break; -#endif + case DW_AT_type: /* Recurse. */ - if (uvalue >= (size_t) (end - start)) - return; - /* We cannot correctly process DW_FORM_ref_addr at the moment. */ - if (attr->form != DW_FORM_ref_addr) - get_type_signedness (start, start + uvalue, end, pointer_size, - offset_size, dwarf_version, is_signed, nesting + 1); + { + abbrev_entry * type_abbrev; + unsigned char * type_data; + unsigned long type_cu_offset; + + 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; case DW_AT_encoding: @@ -2276,12 +2483,12 @@ read_and_display_attr_value (unsigned long attribute, { case DW_FORM_ref_addr: if (!do_loc) - printf ("%c<0x%s>", delimiter, dwarf_vmatoa ("x",uvalue)); + printf ("%c<0x%s>", delimiter, dwarf_vmatoa ("x", uvalue)); break; case DW_FORM_GNU_ref_alt: if (!do_loc) - printf ("%c", delimiter, dwarf_vmatoa ("x",uvalue)); + printf ("%c", delimiter, dwarf_vmatoa ("x", uvalue)); /* FIXME: Follow the reference... */ break; @@ -2667,11 +2874,18 @@ read_and_display_attr_value (unsigned long attribute, && uvalue < (size_t) (end - start)) { bfd_boolean is_signed = FALSE; - - /* We cannot correctly process DW_FORM_ref_addr at the moment. */ - if (form != DW_FORM_ref_addr) - get_type_signedness (start, start + uvalue, end, pointer_size, - offset_size, dwarf_version, & is_signed, 0); + abbrev_entry * type_abbrev; + unsigned char * type_data; + unsigned long type_cu_offset; + + type_abbrev = get_type_abbrev_from_form (form, uvalue, cu_offset, + section, NULL, & type_data, & type_cu_offset); + if (type_abbrev != NULL) + { + 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; } break; @@ -2993,40 +3207,22 @@ read_and_display_attr_value (unsigned long attribute, case DW_AT_import: { - if (form == DW_FORM_ref_sig8 - || form == DW_FORM_GNU_ref_alt) - break; + unsigned long abbrev_number; + abbrev_entry *entry; - if (form == DW_FORM_ref1 - || form == DW_FORM_ref2 - || form == DW_FORM_ref4 - || form == DW_FORM_ref_udata) - uvalue += cu_offset; - - 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"), - dwarf_vmatoa ("x", uvalue), - (unsigned long) (orig_data - section->start)); + entry = get_type_abbrev_from_form (form, uvalue, cu_offset, + section, & abbrev_number, NULL, NULL); + if (entry == NULL) + { + if (form != DW_FORM_GNU_ref_alt) + 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), + (unsigned long) (orig_data - section->start)); + } 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); - /* 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 ("]"); } } @@ -3245,8 +3441,98 @@ process_debug_info (struct dwarf_section * section, if (!do_loc && dwarf_start_die == 0) introduce (section, FALSE); + + free_all_abbrevs (); + free (cu_abbrev_map); + cu_abbrev_map = NULL; + next_free_abbrev_map_entry = 0; - for (section_begin = start, unit = 0; start < end; unit++) + /* 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; unsigned char *hdrptr; @@ -3262,6 +3548,7 @@ process_debug_info (struct dwarf_section * section, struct cu_tu_set *this_set; dwarf_vma abbrev_base; size_t abbrev_size; + abbrev_list * list = NULL; hdrptr = start; @@ -3439,8 +3726,6 @@ process_debug_info (struct dwarf_section * section, continue; } - free_abbrevs (); - /* Process the abbrevs used by this compilation unit. */ if (compunit.cu_abbrev_offset >= abbrev_size) 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) debug_displays [abbrev_sec].section.size); else - process_abbrev_section - (((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 = 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 + + 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; + } + } level = 0; last_level = level; @@ -3537,11 +3833,13 @@ process_debug_info (struct dwarf_section * section, /* Scan through the abbreviation list until we reach the correct entry. */ - for (entry = first_abbrev; - entry && entry->entry != abbrev_number; - entry = entry->next) + if (list == NULL) continue; + for (entry = list->first_abbrev; entry != NULL; entry = entry->next) + if (entry->number == abbrev_number) + break; + if (entry == NULL) { if (!do_loc && do_printing) @@ -5763,30 +6061,37 @@ display_debug_abbrev (struct dwarf_section *section, { abbrev_entry *entry; unsigned char *start = section->start; - unsigned char *end = start + section->size; + const unsigned char *end = start + section->size; introduce (section, FALSE); do { - unsigned char *last; + abbrev_list * list; + dwarf_vma offset; - free_abbrevs (); - - last = start; - start = process_abbrev_section (start, end); + 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; - if (first_abbrev == NULL) + if (list->first_abbrev == NULL) 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; printf (" %ld %s [%s]\n", - entry->entry, + entry->number, get_TAG_name (entry->tag), entry->children ? _("has children") : _("no children")); @@ -10828,8 +11133,12 @@ free_debug_memory (void) { 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++) free_debug_section ((enum dwarf_section_display_enum) i);