diff --git a/gdb/block.c b/gdb/block.c
index d8f8bf56de7b1498ae3f89650a3c86c4eafe3bfe..27295168ba564334e5c50c98ad20c66bf2b21aa2 100644
--- a/gdb/block.c
+++ b/gdb/block.c
@@ -669,7 +669,11 @@ block_lookup_symbol (const struct block *block, const lookup_name_info &name,
 		     const domain_search_flags domain)
 {
   if (!block->function ())
-    return block_lookup_symbol_primary (block, name, domain);
+    {
+      best_symbol_tracker tracker;
+      tracker.search (nullptr, block, name, domain);
+      return tracker.currently_best.symbol;
+    }
   else
     {
       /* Note that parameter symbols do not always show up last in the
@@ -700,12 +704,12 @@ block_lookup_symbol (const struct block *block, const lookup_name_info &name,
 
 /* See block.h.  */
 
-struct symbol *
-block_lookup_symbol_primary (const struct block *block,
+bool
+best_symbol_tracker::search (compunit_symtab *symtab,
+			     const struct block *block,
 			     const lookup_name_info &name,
 			     const domain_search_flags domain)
 {
-  symbol *other = nullptr;
   for (symbol *sym : block_iterator_range (block, &name))
     {
       /* With the fix for PR gcc/debug/91507, we get for:
@@ -736,17 +740,28 @@ block_lookup_symbol_primary (const struct block *block,
 	 the only option to make this work is improve the fallback to use the
 	 size of the minimal symbol.  Filed as PR exp/24989.  */
       if (best_symbol (sym, domain))
-	return sym;
+	{
+	  best_symtab = symtab;
+	  currently_best = { sym, block };
+	  return true;
+	}
 
       /* This is a bit of a hack, but 'matches' might ignore
 	 STRUCT vs VAR domain symbols.  So if a matching symbol is found,
 	 make sure there is no "better" matching symbol, i.e., one with
 	 exactly the same domain.  PR 16253.  */
       if (sym->matches (domain))
-	other = better_symbol (other, sym, domain);
+	{
+	  symbol *better = better_symbol (sym, currently_best.symbol, domain);
+	  if (better != currently_best.symbol)
+	    {
+	      best_symtab = symtab;
+	      currently_best = { better, block };
+	    }
+	}
     }
 
-  return other;
+  return false;
 }
 
 /* See block.h.  */
diff --git a/gdb/block.h b/gdb/block.h
index c348c7fdcc4088e7f5c912e49c387e2c650eda45..b1daed216c956043b63ee99d8418607b417593ae 100644
--- a/gdb/block.h
+++ b/gdb/block.h
@@ -630,14 +630,27 @@ extern struct symbol *block_lookup_symbol (const struct block *block,
 					   const lookup_name_info &name,
 					   const domain_search_flags domain);
 
-/* Search BLOCK for symbol NAME in DOMAIN but only in primary symbol table of
-   BLOCK.  BLOCK must be STATIC_BLOCK or GLOBAL_BLOCK.  Function is useful if
-   one iterates all global/static blocks of an objfile.  */
+/* When searching for a symbol, the "best" symbol is preferred over
+   one that is merely acceptable.  See 'best_symbol'.  This class
+   keeps track of this distinction while searching.  */
 
-extern struct symbol *block_lookup_symbol_primary
-     (const struct block *block,
-      const lookup_name_info &name,
-      const domain_search_flags domain);
+struct best_symbol_tracker
+{
+  /* The symtab in which the currently best symbol appears.  */
+  compunit_symtab *best_symtab = nullptr;
+
+  /* The currently best (really "better") symbol.  */
+  block_symbol currently_best {};
+
+  /* Search BLOCK (which must have come from SYMTAB) for a symbol
+     matching NAME and DOMAIN.  When a symbol is found, update
+     'currently_best'.  If a best symbol is found, return true.
+     Otherwise, return false.  SYMTAB can be nullptr if the caller
+     does not care about this tracking.  */
+  bool search (compunit_symtab *symtab,
+	       const block *block, const lookup_name_info &name,
+	       domain_search_flags domain);
+};
 
 /* Find symbol NAME in BLOCK and in DOMAIN.  This will return a
    matching symbol whose type is not a "opaque", see TYPE_IS_OPAQUE.
diff --git a/gdb/symtab.c b/gdb/symtab.c
index eeafcaab49df8ad727980ff99e9e2a8c52043abd..14bc59fc2bfe6f04a22d9fb1b5bfab0f6b13c5e6 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -2366,44 +2366,25 @@ lookup_symbol_in_objfile_symtabs (struct objfile *objfile,
      name, domain_name (domain).c_str ());
 
   lookup_name_info lookup_name (name, symbol_name_match_type::FULL);
-  struct block_symbol other;
-  other.symbol = NULL;
+  best_symbol_tracker accum;
   for (compunit_symtab *cust : objfile->compunits ())
     {
       const struct blockvector *bv;
       const struct block *block;
-      struct block_symbol result;
 
       bv = cust->blockvector ();
       block = bv->block (block_index);
-      result.symbol = block_lookup_symbol_primary (block, lookup_name, domain);
-      result.block = block;
-      if (result.symbol == NULL)
-	continue;
-      if (best_symbol (result.symbol, domain))
-	{
-	  other = result;
-	  break;
-	}
-      if (result.symbol->matches (domain))
-	{
-	  struct symbol *better
-	    = better_symbol (other.symbol, result.symbol, domain);
-	  if (better != other.symbol)
-	    {
-	      other.symbol = better;
-	      other.block = block;
-	    }
-	}
+      if (accum.search (cust, block, lookup_name, domain))
+	break;
     }
 
-  if (other.symbol != NULL)
+  if (accum.currently_best.symbol != nullptr)
     {
       symbol_lookup_debug_printf_v
 	("lookup_symbol_in_objfile_symtabs (...) = %s (block %s)",
-	 host_address_to_string (other.symbol),
-	 host_address_to_string (other.block));
-      return other;
+	 host_address_to_string (accum.currently_best.symbol),
+	 host_address_to_string (accum.currently_best.block));
+      return accum.currently_best;
     }
 
   symbol_lookup_debug_printf_v
