1From f07c08e115e27cddf5a0030dc6332bbee1bd9c6a Mon Sep 17 00:00:00 2001 2From: Alan Modra <amodra@gmail.com> 3Date: Thu, 21 Jul 2022 08:38:14 +0930 4Subject: [PATCH] binutils/dwarf.c: abbrev caching 5 6I'm inclined to think that abbrev caching is counter-productive. The 7time taken to search the list of abbrevs converted to internal form is 8non-zero, and it's easy to decode the raw abbrevs. It's especially 9silly to cache empty lists of decoded abbrevs (happens with zero 10padding in .debug_abbrev), or abbrevs as they are displayed when there 11is no further use of those abbrevs. This patch stops caching in those 12cases. 13 14 * dwarf.c (record_abbrev_list_for_cu): Add free_list param. 15 Put abbrevs on abbrev_lists here. 16 (new_abbrev_list): Delete function. 17 (process_abbrev_set): Return newly allocated list. Move 18 abbrev base, offset and size checking to.. 19 (find_and_process_abbrev_set): ..here, new function. Handle 20 lookup of cached abbrevs here, and calculate start and end 21 for process_abbrev_set. Return free_list if newly alloc'd. 22 (process_debug_info): Consolidate cached list lookup, new list 23 alloc and processing into find_and_process_abbrev_set call. 24 Free list when not cached. 25 (display_debug_abbrev): Similarly. 26 27Upstream-Status: Backport [https://sourceware.org/git/?p=binutils-gdb.git;a=commitdiff;h=f07c08e115e27cddf5a0030dc6332bbee1bd9c6a] 28 29Signed-off-by: Pgowda <pgowda.cve@gmail.com> 30--- 31 binutils/dwarf.c | 208 +++++++++++++++++++++++++---------------------- 32 1 file changed, 110 insertions(+), 98 deletions(-) 33 34diff --git a/binutils/dwarf.c b/binutils/dwarf.c 35index 267ed3bb382..2fc352f74c5 100644 36--- a/binutils/dwarf.c 37+++ b/binutils/dwarf.c 38@@ -882,8 +882,15 @@ static unsigned long next_free_abbrev_m 39 #define ABBREV_MAP_ENTRIES_INCREMENT 8 40 41 static void 42-record_abbrev_list_for_cu (dwarf_vma start, dwarf_vma end, abbrev_list * list) 43+record_abbrev_list_for_cu (dwarf_vma start, dwarf_vma end, 44+ abbrev_list *list, abbrev_list *free_list) 45 { 46+ if (free_list != NULL) 47+ { 48+ list->next = abbrev_lists; 49+ abbrev_lists = list; 50+ } 51+ 52 if (cu_abbrev_map == NULL) 53 { 54 num_abbrev_map_entries = INITIAL_NUM_ABBREV_MAP_ENTRIES; 55@@ -936,20 +943,6 @@ free_all_abbrevs (void) 56 } 57 58 static abbrev_list * 59-new_abbrev_list (dwarf_vma abbrev_base, dwarf_vma abbrev_offset) 60-{ 61- abbrev_list * list = (abbrev_list *) xcalloc (sizeof * list, 1); 62- 63- list->abbrev_base = abbrev_base; 64- list->abbrev_offset = abbrev_offset; 65- 66- list->next = abbrev_lists; 67- abbrev_lists = list; 68- 69- return list; 70-} 71- 72-static abbrev_list * 73 find_abbrev_list_by_abbrev_offset (dwarf_vma abbrev_base, 74 dwarf_vma abbrev_offset) 75 { 76@@ -966,7 +959,7 @@ find_abbrev_list_by_abbrev_offset (dwarf 77 /* Find the abbreviation map for the CU that includes OFFSET. 78 OFFSET is an absolute offset from the start of the .debug_info section. */ 79 /* FIXME: This function is going to slow down readelf & objdump. 80- Consider using a better algorithm to mitigate this effect. */ 81+ Not caching abbrevs is likely the answer. */ 82 83 static abbrev_map * 84 find_abbrev_map_by_offset (dwarf_vma offset) 85@@ -1033,40 +1026,18 @@ add_abbrev_attr (unsigned long attrib 86 list->last_abbrev->last_attr = attr; 87 } 88 89-/* Processes the (partial) contents of a .debug_abbrev section. 90- Returns NULL if the end of the section was encountered. 91- Returns the address after the last byte read if the end of 92- an abbreviation set was found. */ 93+/* Return processed (partial) contents of a .debug_abbrev section. 94+ Returns NULL on errors. */ 95 96-static unsigned char * 97+static abbrev_list * 98 process_abbrev_set (struct dwarf_section *section, 99- dwarf_vma abbrev_base, 100- dwarf_vma abbrev_size, 101- dwarf_vma abbrev_offset, 102- abbrev_list *list) 103+ unsigned char *start, 104+ unsigned char *end) 105 { 106- if (abbrev_base >= section->size 107- || abbrev_size > section->size - abbrev_base) 108- { 109- /* PR 17531: file:4bcd9ce9. */ 110- warn (_("Debug info is corrupted, abbrev size (%lx) is larger than " 111- "abbrev section size (%lx)\n"), 112- (unsigned long) (abbrev_base + abbrev_size), 113- (unsigned long) section->size); 114- return NULL; 115- } 116- if (abbrev_offset >= abbrev_size) 117- { 118- warn (_("Debug info is corrupted, abbrev offset (%lx) is larger than " 119- "abbrev section size (%lx)\n"), 120- (unsigned long) abbrev_offset, 121- (unsigned long) abbrev_size); 122- return NULL; 123- } 124+ abbrev_list *list = xmalloc (sizeof (*list)); 125+ list->first_abbrev = NULL; 126+ list->last_abbrev = NULL; 127 128- unsigned char *start = section->start + abbrev_base; 129- unsigned char *end = start + abbrev_size; 130- start += abbrev_offset; 131 while (start < end) 132 { 133 unsigned long entry; 134@@ -1079,14 +1050,18 @@ process_abbrev_set (struct dwarf_section 135 /* A single zero is supposed to end the set according 136 to the standard. If there's more, then signal that to 137 the caller. */ 138- if (start == end) 139- return NULL; 140- if (entry == 0) 141- return start; 142+ if (start == end || entry == 0) 143+ { 144+ list->start_of_next_abbrevs = start != end ? start : NULL; 145+ return list; 146+ } 147 148 READ_ULEB (tag, start, end); 149 if (start == end) 150- return NULL; 151+ { 152+ free (list); 153+ return NULL; 154+ } 155 156 children = *start++; 157 158@@ -1121,9 +1096,67 @@ process_abbrev_set (struct dwarf_section 159 /* Report the missing single zero which ends the section. */ 160 error (_(".debug_abbrev section not zero terminated\n")); 161 162+ free (list); 163 return NULL; 164 } 165 166+/* Return a sequence of abbrevs in SECTION starting at ABBREV_BASE 167+ plus ABBREV_OFFSET and finishing at ABBREV_BASE + ABBREV_SIZE. 168+ If FREE_LIST is non-NULL search the already decoded abbrevs on 169+ abbrev_lists first and if found set *FREE_LIST to NULL. If 170+ searching doesn't find a matching abbrev, set *FREE_LIST to the 171+ newly allocated list. If FREE_LIST is NULL, no search is done and 172+ the returned abbrev_list is always newly allocated. */ 173+ 174+static abbrev_list * 175+find_and_process_abbrev_set (struct dwarf_section *section, 176+ dwarf_vma abbrev_base, 177+ dwarf_vma abbrev_size, 178+ dwarf_vma abbrev_offset, 179+ abbrev_list **free_list) 180+{ 181+ if (free_list) 182+ *free_list = NULL; 183+ 184+ if (abbrev_base >= section->size 185+ || abbrev_size > section->size - abbrev_base) 186+ { 187+ /* PR 17531: file:4bcd9ce9. */ 188+ warn (_("Debug info is corrupted, abbrev size (%lx) is larger than " 189+ "abbrev section size (%lx)\n"), 190+ (unsigned long) (abbrev_base + abbrev_size), 191+ (unsigned long) section->size); 192+ return NULL; 193+ } 194+ if (abbrev_offset >= abbrev_size) 195+ { 196+ warn (_("Debug info is corrupted, abbrev offset (%lx) is larger than " 197+ "abbrev section size (%lx)\n"), 198+ (unsigned long) abbrev_offset, 199+ (unsigned long) abbrev_size); 200+ return NULL; 201+ } 202+ 203+ unsigned char *start = section->start + abbrev_base + abbrev_offset; 204+ unsigned char *end = section->start + abbrev_base + abbrev_size; 205+ abbrev_list *list = NULL; 206+ if (free_list) 207+ list = find_abbrev_list_by_abbrev_offset (abbrev_base, abbrev_offset); 208+ if (list == NULL) 209+ { 210+ list = process_abbrev_set (section, start, end); 211+ if (list) 212+ { 213+ list->abbrev_base = abbrev_base; 214+ list->abbrev_offset = abbrev_offset; 215+ list->next = NULL; 216+ } 217+ if (free_list) 218+ *free_list = list; 219+ } 220+ return list; 221+} 222+ 223 static const char * 224 get_TAG_name (unsigned long tag) 225 { 226@@ -3670,7 +3703,6 @@ process_debug_info (struct dwarf_section 227 dwarf_vma cu_offset; 228 unsigned int offset_size; 229 struct cu_tu_set * this_set; 230- abbrev_list * list; 231 unsigned char *end_cu; 232 233 hdrptr = start; 234@@ -3726,22 +3758,18 @@ process_debug_info (struct dwarf_section 235 abbrev_size = this_set->section_sizes [DW_SECT_ABBREV]; 236 } 237 238- list = find_abbrev_list_by_abbrev_offset (abbrev_base, 239- compunit.cu_abbrev_offset); 240- if (list == NULL) 241- { 242- unsigned char * next; 243- 244- list = new_abbrev_list (abbrev_base, 245- compunit.cu_abbrev_offset); 246- next = process_abbrev_set (&debug_displays[abbrev_sec].section, 247- abbrev_base, abbrev_size, 248- compunit.cu_abbrev_offset, list); 249- list->start_of_next_abbrevs = next; 250- } 251- 252+ abbrev_list *list; 253+ abbrev_list *free_list; 254+ list = find_and_process_abbrev_set (&debug_displays[abbrev_sec].section, 255+ abbrev_base, abbrev_size, 256+ compunit.cu_abbrev_offset, 257+ &free_list); 258 start = end_cu; 259- record_abbrev_list_for_cu (cu_offset, start - section_begin, list); 260+ if (list != NULL && list->first_abbrev != NULL) 261+ record_abbrev_list_for_cu (cu_offset, start - section_begin, 262+ list, free_list); 263+ else if (free_list != NULL) 264+ free_abbrev_list (free_list); 265 } 266 267 for (start = section_begin, unit = 0; start < end; unit++) 268@@ -3757,7 +3785,6 @@ process_debug_info (struct dwarf_section 269 struct cu_tu_set *this_set; 270 dwarf_vma abbrev_base; 271 size_t abbrev_size; 272- abbrev_list * list = NULL; 273 unsigned char *end_cu; 274 275 hdrptr = start; 276@@ -3936,20 +3963,10 @@ process_debug_info (struct dwarf_section 277 } 278 279 /* Process the abbrevs used by this compilation unit. */ 280- list = find_abbrev_list_by_abbrev_offset (abbrev_base, 281- compunit.cu_abbrev_offset); 282- if (list == NULL) 283- { 284- unsigned char *next; 285- 286- list = new_abbrev_list (abbrev_base, 287- compunit.cu_abbrev_offset); 288- next = process_abbrev_set (&debug_displays[abbrev_sec].section, 289- abbrev_base, abbrev_size, 290- compunit.cu_abbrev_offset, list); 291- list->start_of_next_abbrevs = next; 292- } 293- 294+ abbrev_list *list; 295+ list = find_and_process_abbrev_set (&debug_displays[abbrev_sec].section, 296+ abbrev_base, abbrev_size, 297+ compunit.cu_abbrev_offset, NULL); 298 level = 0; 299 last_level = level; 300 saved_level = -1; 301@@ -4128,6 +4145,8 @@ process_debug_info (struct dwarf_section 302 if (entry->children) 303 ++level; 304 } 305+ if (list != NULL) 306+ free_abbrev_list (list); 307 } 308 309 /* Set num_debug_info_entries here so that it can be used to check if 310@@ -6353,24 +6372,15 @@ display_debug_abbrev (struct dwarf_secti 311 312 do 313 { 314- abbrev_list * list; 315- dwarf_vma offset; 316- 317- offset = start - section->start; 318- list = find_abbrev_list_by_abbrev_offset (0, offset); 319+ dwarf_vma offset = start - section->start; 320+ abbrev_list *list = find_and_process_abbrev_set (section, 0, 321+ section->size, offset, 322+ NULL); 323 if (list == NULL) 324- { 325- list = new_abbrev_list (0, offset); 326- start = process_abbrev_set (section, 0, section->size, offset, list); 327- list->start_of_next_abbrevs = start; 328- } 329- else 330- start = list->start_of_next_abbrevs; 331- 332- if (list->first_abbrev == NULL) 333- continue; 334+ break; 335 336- printf (_(" Number TAG (0x%lx)\n"), (long) offset); 337+ if (list->first_abbrev) 338+ printf (_(" Number TAG (0x%lx)\n"), (long) offset); 339 340 for (entry = list->first_abbrev; entry; entry = entry->next) 341 { 342@@ -6391,6 +6401,8 @@ display_debug_abbrev (struct dwarf_secti 343 putchar ('\n'); 344 } 345 } 346+ start = list->start_of_next_abbrevs; 347+ free_abbrev_list (list); 348 } 349 while (start); 350 351