blob: 0a490d86b36d8f551340764c1075f178c93dd009 [file] [log] [blame]
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001From 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