From f07c08e115e27cddf5a0030dc6332bbee1bd9c6a Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Thu, 21 Jul 2022 08:38:14 +0930 Subject: [PATCH] binutils/dwarf.c: abbrev caching I'm inclined to think that abbrev caching is counter-productive. The time taken to search the list of abbrevs converted to internal form is non-zero, and it's easy to decode the raw abbrevs. It's especially silly to cache empty lists of decoded abbrevs (happens with zero padding in .debug_abbrev), or abbrevs as they are displayed when there is no further use of those abbrevs. This patch stops caching in those cases. * dwarf.c (record_abbrev_list_for_cu): Add free_list param. Put abbrevs on abbrev_lists here. (new_abbrev_list): Delete function. (process_abbrev_set): Return newly allocated list. Move abbrev base, offset and size checking to.. (find_and_process_abbrev_set): ..here, new function. Handle lookup of cached abbrevs here, and calculate start and end for process_abbrev_set. Return free_list if newly alloc'd. (process_debug_info): Consolidate cached list lookup, new list alloc and processing into find_and_process_abbrev_set call. Free list when not cached. (display_debug_abbrev): Similarly. Upstream-Status: Backport [https://sourceware.org/git/?p=binutils-gdb.git;a=commitdiff;h=f07c08e115e27cddf5a0030dc6332bbee1bd9c6a] Signed-off-by: Pgowda --- binutils/dwarf.c | 208 +++++++++++++++++++++++++---------------------- 1 file changed, 110 insertions(+), 98 deletions(-) diff --git a/binutils/dwarf.c b/binutils/dwarf.c index 267ed3bb382..2fc352f74c5 100644 --- a/binutils/dwarf.c +++ b/binutils/dwarf.c @@ -882,8 +882,15 @@ static unsigned long next_free_abbrev_m #define ABBREV_MAP_ENTRIES_INCREMENT 8 static void -record_abbrev_list_for_cu (dwarf_vma start, dwarf_vma end, abbrev_list * list) +record_abbrev_list_for_cu (dwarf_vma start, dwarf_vma end, + abbrev_list *list, abbrev_list *free_list) { + if (free_list != NULL) + { + list->next = abbrev_lists; + abbrev_lists = list; + } + if (cu_abbrev_map == NULL) { num_abbrev_map_entries = INITIAL_NUM_ABBREV_MAP_ENTRIES; @@ -936,20 +943,6 @@ free_all_abbrevs (void) } static abbrev_list * -new_abbrev_list (dwarf_vma abbrev_base, dwarf_vma abbrev_offset) -{ - abbrev_list * list = (abbrev_list *) xcalloc (sizeof * list, 1); - - list->abbrev_base = abbrev_base; - 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_base, dwarf_vma abbrev_offset) { @@ -966,7 +959,7 @@ find_abbrev_list_by_abbrev_offset (dwarf /* 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. */ + Not caching abbrevs is likely the answer. */ static abbrev_map * find_abbrev_map_by_offset (dwarf_vma offset) @@ -1033,40 +1026,18 @@ add_abbrev_attr (unsigned long attrib list->last_abbrev->last_attr = attr; } -/* Processes the (partial) contents of a .debug_abbrev section. - Returns NULL if the end of the section was encountered. - Returns the address after the last byte read if the end of - an abbreviation set was found. */ +/* Return processed (partial) contents of a .debug_abbrev section. + Returns NULL on errors. */ -static unsigned char * +static abbrev_list * process_abbrev_set (struct dwarf_section *section, - dwarf_vma abbrev_base, - dwarf_vma abbrev_size, - dwarf_vma abbrev_offset, - abbrev_list *list) + unsigned char *start, + unsigned char *end) { - if (abbrev_base >= section->size - || abbrev_size > section->size - abbrev_base) - { - /* PR 17531: file:4bcd9ce9. */ - warn (_("Debug info is corrupted, abbrev size (%lx) is larger than " - "abbrev section size (%lx)\n"), - (unsigned long) (abbrev_base + abbrev_size), - (unsigned long) section->size); - return NULL; - } - if (abbrev_offset >= abbrev_size) - { - warn (_("Debug info is corrupted, abbrev offset (%lx) is larger than " - "abbrev section size (%lx)\n"), - (unsigned long) abbrev_offset, - (unsigned long) abbrev_size); - return NULL; - } + abbrev_list *list = xmalloc (sizeof (*list)); + list->first_abbrev = NULL; + list->last_abbrev = NULL; - unsigned char *start = section->start + abbrev_base; - unsigned char *end = start + abbrev_size; - start += abbrev_offset; while (start < end) { unsigned long entry; @@ -1079,14 +1050,18 @@ process_abbrev_set (struct dwarf_section /* 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) - return NULL; - if (entry == 0) - return start; + if (start == end || entry == 0) + { + list->start_of_next_abbrevs = start != end ? start : NULL; + return list; + } READ_ULEB (tag, start, end); if (start == end) - return NULL; + { + free (list); + return NULL; + } children = *start++; @@ -1121,9 +1096,67 @@ process_abbrev_set (struct dwarf_section /* Report the missing single zero which ends the section. */ error (_(".debug_abbrev section not zero terminated\n")); + free (list); return NULL; } +/* Return a sequence of abbrevs in SECTION starting at ABBREV_BASE + plus ABBREV_OFFSET and finishing at ABBREV_BASE + ABBREV_SIZE. + If FREE_LIST is non-NULL search the already decoded abbrevs on + abbrev_lists first and if found set *FREE_LIST to NULL. If + searching doesn't find a matching abbrev, set *FREE_LIST to the + newly allocated list. If FREE_LIST is NULL, no search is done and + the returned abbrev_list is always newly allocated. */ + +static abbrev_list * +find_and_process_abbrev_set (struct dwarf_section *section, + dwarf_vma abbrev_base, + dwarf_vma abbrev_size, + dwarf_vma abbrev_offset, + abbrev_list **free_list) +{ + if (free_list) + *free_list = NULL; + + if (abbrev_base >= section->size + || abbrev_size > section->size - abbrev_base) + { + /* PR 17531: file:4bcd9ce9. */ + warn (_("Debug info is corrupted, abbrev size (%lx) is larger than " + "abbrev section size (%lx)\n"), + (unsigned long) (abbrev_base + abbrev_size), + (unsigned long) section->size); + return NULL; + } + if (abbrev_offset >= abbrev_size) + { + warn (_("Debug info is corrupted, abbrev offset (%lx) is larger than " + "abbrev section size (%lx)\n"), + (unsigned long) abbrev_offset, + (unsigned long) abbrev_size); + return NULL; + } + + unsigned char *start = section->start + abbrev_base + abbrev_offset; + unsigned char *end = section->start + abbrev_base + abbrev_size; + abbrev_list *list = NULL; + if (free_list) + list = find_abbrev_list_by_abbrev_offset (abbrev_base, abbrev_offset); + if (list == NULL) + { + list = process_abbrev_set (section, start, end); + if (list) + { + list->abbrev_base = abbrev_base; + list->abbrev_offset = abbrev_offset; + list->next = NULL; + } + if (free_list) + *free_list = list; + } + return list; +} + static const char * get_TAG_name (unsigned long tag) { @@ -3670,7 +3703,6 @@ process_debug_info (struct dwarf_section dwarf_vma cu_offset; unsigned int offset_size; struct cu_tu_set * this_set; - abbrev_list * list; unsigned char *end_cu; hdrptr = start; @@ -3726,22 +3758,18 @@ process_debug_info (struct dwarf_section abbrev_size = this_set->section_sizes [DW_SECT_ABBREV]; } - list = find_abbrev_list_by_abbrev_offset (abbrev_base, - compunit.cu_abbrev_offset); - if (list == NULL) - { - unsigned char * next; - - list = new_abbrev_list (abbrev_base, - compunit.cu_abbrev_offset); - next = process_abbrev_set (&debug_displays[abbrev_sec].section, - abbrev_base, abbrev_size, - compunit.cu_abbrev_offset, list); - list->start_of_next_abbrevs = next; - } - + abbrev_list *list; + abbrev_list *free_list; + list = find_and_process_abbrev_set (&debug_displays[abbrev_sec].section, + abbrev_base, abbrev_size, + compunit.cu_abbrev_offset, + &free_list); start = end_cu; - record_abbrev_list_for_cu (cu_offset, start - section_begin, list); + if (list != NULL && list->first_abbrev != NULL) + record_abbrev_list_for_cu (cu_offset, start - section_begin, + list, free_list); + else if (free_list != NULL) + free_abbrev_list (free_list); } for (start = section_begin, unit = 0; start < end; unit++) @@ -3757,7 +3785,6 @@ process_debug_info (struct dwarf_section struct cu_tu_set *this_set; dwarf_vma abbrev_base; size_t abbrev_size; - abbrev_list * list = NULL; unsigned char *end_cu; hdrptr = start; @@ -3936,20 +3963,10 @@ process_debug_info (struct dwarf_section } /* Process the abbrevs used by this compilation unit. */ - list = find_abbrev_list_by_abbrev_offset (abbrev_base, - compunit.cu_abbrev_offset); - if (list == NULL) - { - unsigned char *next; - - list = new_abbrev_list (abbrev_base, - compunit.cu_abbrev_offset); - next = process_abbrev_set (&debug_displays[abbrev_sec].section, - abbrev_base, abbrev_size, - compunit.cu_abbrev_offset, list); - list->start_of_next_abbrevs = next; - } - + abbrev_list *list; + list = find_and_process_abbrev_set (&debug_displays[abbrev_sec].section, + abbrev_base, abbrev_size, + compunit.cu_abbrev_offset, NULL); level = 0; last_level = level; saved_level = -1; @@ -4128,6 +4145,8 @@ process_debug_info (struct dwarf_section if (entry->children) ++level; } + if (list != NULL) + free_abbrev_list (list); } /* Set num_debug_info_entries here so that it can be used to check if @@ -6353,24 +6372,15 @@ display_debug_abbrev (struct dwarf_secti do { - abbrev_list * list; - dwarf_vma offset; - - offset = start - section->start; - list = find_abbrev_list_by_abbrev_offset (0, offset); + dwarf_vma offset = start - section->start; + abbrev_list *list = find_and_process_abbrev_set (section, 0, + section->size, offset, + NULL); if (list == NULL) - { - list = new_abbrev_list (0, offset); - start = process_abbrev_set (section, 0, section->size, offset, list); - list->start_of_next_abbrevs = start; - } - else - start = list->start_of_next_abbrevs; - - if (list->first_abbrev == NULL) - continue; + break; - printf (_(" Number TAG (0x%lx)\n"), (long) offset); + if (list->first_abbrev) + printf (_(" Number TAG (0x%lx)\n"), (long) offset); for (entry = list->first_abbrev; entry; entry = entry->next) { @@ -6391,6 +6401,8 @@ display_debug_abbrev (struct dwarf_secti putchar ('\n'); } } + start = list->start_of_next_abbrevs; + free_abbrev_list (list); } while (start);