blob: 0a490d86b36d8f551340764c1075f178c93dd009 [file] [log] [blame]
From f07c08e115e27cddf5a0030dc6332bbee1bd9c6a Mon Sep 17 00:00:00 2001
From: Alan Modra <amodra@gmail.com>
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 <pgowda.cve@gmail.com>
---
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);