Introduce gdb_bfd_canonicalize_symtab

bfd_canonicalize_symtab stores the symbols in the BFD, and returns
pointers to these.  The ELF reader does not reuse these stored
symbols, so each call to bfd_canonicalize_symtab causes an allocation.

This interacts poorly with code like arm_pikeos_osabi_sniffer, which
searches the BFD symbol when called.

PR gdb/32758 points out a particularly pathological case: using "maint
info sections" on a program with a large number of sections (10000)
will cause 10000 calls to arm_pikeos_osabi_sniffer, allocating 20G.

I'm not sure BFD always worked this way.  And, fixing BFD was an
option.  However it seemed maybe better for GDB to adapt, since
adapting would mean that the fix would apply to all BFD back ends, and
not just ELF.

To that end, this patch adds a new gdb_bfd_canonicalize_symtab and
changes all callers of bfd_canonicalize_symtab to use it instead.
This new function caches the result in the per-BFD object.

I looked into having this return a view of "const asymbol *".  However
both the compile module and machoread modify the returned symbols.
And while I think this is wrong, I haven't tried to fix this here.

Regression tested on x86-64 Fedora 40.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=32758
This commit is contained in:
Tom Tromey
2025-03-06 10:59:41 -07:00
parent 15bbe2b14c
commit 89e59ca6dc
8 changed files with 123 additions and 142 deletions

View File

@@ -605,9 +605,7 @@ compile_object_load (const compile_file_names &file_names,
CORE_ADDR regs_addr, out_value_addr = 0;
struct symbol *func_sym;
struct type *func_type;
long storage_needed;
asymbol **symbol_table, **symp;
long number_of_symbols, missing_symbols;
long missing_symbols;
struct type *regs_type, *out_value_type = NULL;
char **matching;
struct objfile *objfile;
@@ -635,11 +633,6 @@ compile_object_load (const compile_file_names &file_names,
setup_sections_data.setup_one_section (sect);
setup_sections_data.setup_one_section (nullptr);
storage_needed = bfd_get_symtab_upper_bound (abfd.get ());
if (storage_needed < 0)
error (_("Cannot read symbols of compiled module \"%s\": %s"),
filename.get (), bfd_errmsg (bfd_get_error ()));
/* SYMFILE_VERBOSE is not passed even if FROM_TTY, user is not interested in
"Reading symbols from ..." message for automatically generated file. */
scoped_objfile_unlinker objfile_holder (symbol_file_add_from_bfd
@@ -692,21 +685,12 @@ compile_object_load (const compile_file_names &file_names,
"module \"%s\"."),
GCC_FE_WRAPPER_FUNCTION, objfile_name (objfile));
/* The memory may be later needed
by bfd_generic_get_relocated_section_contents
called from default_symfile_relocate. */
symbol_table = (asymbol **) obstack_alloc (&objfile->objfile_obstack,
storage_needed);
number_of_symbols = bfd_canonicalize_symtab (abfd.get (), symbol_table);
if (number_of_symbols < 0)
error (_("Cannot parse symbols of compiled module \"%s\": %s"),
filename.get (), bfd_errmsg (bfd_get_error ()));
gdb::array_view<asymbol *> symbol_table
= gdb_bfd_canonicalize_symtab (abfd.get ());
missing_symbols = 0;
for (symp = symbol_table; symp < symbol_table + number_of_symbols; symp++)
for (asymbol *sym : symbol_table)
{
asymbol *sym = *symp;
if (sym->flags != 0)
continue;
sym->flags = BSF_GLOBAL;
@@ -800,7 +784,7 @@ compile_object_load (const compile_file_names &file_names,
if (missing_symbols)
error (_("%ld symbols were missing, cannot continue."), missing_symbols);
bfd_map_over_sections (abfd.get (), copy_sections, symbol_table);
bfd_map_over_sections (abfd.get (), copy_sections, symbol_table.data ());
regs_type = get_regs_type (func_sym, objfile);
if (regs_type == NULL)