gdb: add target_ops::supports_displaced_step
[deliverable/binutils-gdb.git] / gdb / symtab.c
index 4c14edae177668c41a159a97dbd1629136774214..791ce11a7372c11583eec384b5d44bf13d4366ea 100644 (file)
@@ -1,6 +1,6 @@
 /* Symbol table lookup for the GNU debugger, GDB.
 
-   Copyright (C) 1986-2019 Free Software Foundation, Inc.
+   Copyright (C) 1986-2020 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -183,6 +183,16 @@ struct symbol_cache_slot
   } value;
 };
 
+/* Clear out SLOT.  */
+
+static void
+symbol_cache_clear_slot (struct symbol_cache_slot *slot)
+{
+  if (slot->state == SYMBOL_SLOT_NOT_FOUND)
+    xfree (slot->value.not_found.name);
+  slot->state = SYMBOL_SLOT_UNUSED;
+}
+
 /* Symbols don't specify global vs static block.
    So keep them in separate caches.  */
 
@@ -201,6 +211,19 @@ struct block_symbol_cache
   struct symbol_cache_slot symbols[1];
 };
 
+/* Clear all slots of BSC and free BSC.  */
+
+static void
+destroy_block_symbol_cache (struct block_symbol_cache *bsc)
+{
+  if (bsc != nullptr)
+    {
+      for (unsigned int i = 0; i < bsc->size; i++)
+       symbol_cache_clear_slot (&bsc->symbols[i]);
+      xfree (bsc);
+    }
+}
+
 /* The symbol cache.
 
    Searching for symbols in the static and global blocks over multiple objfiles
@@ -217,8 +240,8 @@ struct symbol_cache
 
   ~symbol_cache ()
   {
-    xfree (global_symbols);
-    xfree (static_symbols);
+    destroy_block_symbol_cache (global_symbols);
+    destroy_block_symbol_cache (static_symbols);
   }
 
   struct block_symbol_cache *global_symbols = nullptr;
@@ -572,7 +595,7 @@ gdb_mangle_name (struct type *type, int method_id, int signature_id)
   struct fn_field *method = &f[signature_id];
   const char *field_name = TYPE_FN_FIELDLIST_NAME (type, method_id);
   const char *physname = TYPE_FN_FIELD_PHYSNAME (f, signature_id);
-  const char *newname = TYPE_NAME (type);
+  const char *newname = type->name ();
 
   /* Does the form of physname indicate that it is the full mangled name
      of a constructor (not just the args)?  */
@@ -644,44 +667,27 @@ gdb_mangle_name (struct type *type, int method_id, int signature_id)
   return (mangled_name);
 }
 
-/* Set the demangled name of GSYMBOL to NAME.  NAME must be already
-   correctly allocated.  */
+/* See symtab.h.  */
 
 void
-symbol_set_demangled_name (struct general_symbol_info *gsymbol,
-                           const char *name,
-                           struct obstack *obstack)
+general_symbol_info::set_demangled_name (const char *name,
+                                        struct obstack *obstack)
 {
-  if (gsymbol->language == language_ada)
+  if (language () == language_ada)
     {
       if (name == NULL)
        {
-         gsymbol->ada_mangled = 0;
-         gsymbol->language_specific.obstack = obstack;
+         ada_mangled = 0;
+         language_specific.obstack = obstack;
        }
       else
        {
-         gsymbol->ada_mangled = 1;
-         gsymbol->language_specific.demangled_name = name;
+         ada_mangled = 1;
+         language_specific.demangled_name = name;
        }
     }
   else
-    gsymbol->language_specific.demangled_name = name;
-}
-
-/* Return the demangled name of GSYMBOL.  */
-
-const char *
-symbol_get_demangled_name (const struct general_symbol_info *gsymbol)
-{
-  if (gsymbol->language == language_ada)
-    {
-      if (!gsymbol->ada_mangled)
-       return NULL;
-      /* Fall through.  */
-    }
-
-  return gsymbol->language_specific.demangled_name;
+    language_specific.demangled_name = name;
 }
 
 \f
@@ -689,28 +695,26 @@ symbol_get_demangled_name (const struct general_symbol_info *gsymbol)
    depending upon the language for the symbol.  */
 
 void
-symbol_set_language (struct general_symbol_info *gsymbol,
-                     enum language language,
-                    struct obstack *obstack)
+general_symbol_info::set_language (enum language language,
+                                  struct obstack *obstack)
 {
-  gsymbol->language = language;
-  if (gsymbol->language == language_cplus
-      || gsymbol->language == language_d
-      || gsymbol->language == language_go
-      || gsymbol->language == language_objc
-      || gsymbol->language == language_fortran)
+  m_language = language;
+  if (language == language_cplus
+      || language == language_d
+      || language == language_go
+      || language == language_objc
+      || language == language_fortran)
     {
-      symbol_set_demangled_name (gsymbol, NULL, obstack);
+      set_demangled_name (NULL, obstack);
     }
-  else if (gsymbol->language == language_ada)
+  else if (language == language_ada)
     {
-      gdb_assert (gsymbol->ada_mangled == 0);
-      gsymbol->language_specific.obstack = obstack;
+      gdb_assert (ada_mangled == 0);
+      language_specific.obstack = obstack;
     }
   else
     {
-      memset (&gsymbol->language_specific, 0,
-             sizeof (gsymbol->language_specific));
+      memset (&language_specific, 0, sizeof (language_specific));
     }
 }
 
@@ -770,34 +774,40 @@ create_demangled_names_hash (struct objfile_per_bfd_storage *per_bfd)
   /* Choose 256 as the starting size of the hash table, somewhat arbitrarily.
      The hash table code will round this up to the next prime number.
      Choosing a much larger table size wastes memory, and saves only about
-     1% in symbol reading.  */
+     1% in symbol reading.  However, if the minsym count is already
+     initialized (e.g. because symbol name setting was deferred to
+     a background thread) we can initialize the hashtable with a count
+     based on that, because we will almost certainly have at least that
+     many entries.  If we have a nonzero number but less than 256,
+     we still stay with 256 to have some space for psymbols, etc.  */
+
+  /* htab will expand the table when it is 3/4th full, so we account for that
+     here.  +2 to round up.  */
+  int minsym_based_count = (per_bfd->minimal_symbol_count + 2) / 3 * 4;
+  int count = std::max (per_bfd->minimal_symbol_count, minsym_based_count);
 
   per_bfd->demangled_names_hash.reset (htab_create_alloc
-    (256, hash_demangled_name_entry, eq_demangled_name_entry,
+    (count, hash_demangled_name_entry, eq_demangled_name_entry,
      free_demangled_name_entry, xcalloc, xfree));
 }
 
-/* Try to determine the demangled name for a symbol, based on the
-   language of that symbol.  If the language is set to language_auto,
-   it will attempt to find any demangling algorithm that works and
-   then set the language appropriately.  The returned name is allocated
-   by the demangler and should be xfree'd.  */
+/* See symtab.h  */
 
-static char *
+char *
 symbol_find_demangled_name (struct general_symbol_info *gsymbol,
                            const char *mangled)
 {
   char *demangled = NULL;
   int i;
 
-  if (gsymbol->language == language_unknown)
-    gsymbol->language = language_auto;
+  if (gsymbol->language () == language_unknown)
+    gsymbol->m_language = language_auto;
 
-  if (gsymbol->language != language_auto)
+  if (gsymbol->language () != language_auto)
     {
-      const struct language_defn *lang = language_def (gsymbol->language);
+      const struct language_defn *lang = language_def (gsymbol->language ());
 
-      language_sniff_from_mangled_name (lang, mangled, &demangled);
+      lang->sniff_from_mangled_name (mangled, &demangled);
       return demangled;
     }
 
@@ -806,9 +816,9 @@ symbol_find_demangled_name (struct general_symbol_info *gsymbol,
       enum language l = (enum language) i;
       const struct language_defn *lang = language_def (l);
 
-      if (language_sniff_from_mangled_name (lang, mangled, &demangled))
+      if (lang->sniff_from_mangled_name (mangled, &demangled))
        {
-         gsymbol->language = l;
+         gsymbol->m_language = l;
          return demangled;
        }
     }
@@ -828,28 +838,24 @@ symbol_find_demangled_name (struct general_symbol_info *gsymbol,
    so the pointer can be discarded after calling this function.  */
 
 void
-symbol_set_names (struct general_symbol_info *gsymbol,
-                 gdb::string_view linkage_name, bool copy_name,
-                 struct objfile_per_bfd_storage *per_bfd)
+general_symbol_info::compute_and_set_names (gdb::string_view linkage_name,
+                                           bool copy_name,
+                                           objfile_per_bfd_storage *per_bfd,
+                                           gdb::optional<hashval_t> hash)
 {
   struct demangled_name_entry **slot;
 
-  if (gsymbol->language == language_ada)
+  if (language () == language_ada)
     {
       /* In Ada, we do the symbol lookups using the mangled name, so
          we can save some space by not storing the demangled name.  */
       if (!copy_name)
-       gsymbol->name = linkage_name.data ();
+       m_name = linkage_name.data ();
       else
-       {
-         char *name = (char *) obstack_alloc (&per_bfd->storage_obstack,
-                                              linkage_name.length () + 1);
-
-         memcpy (name, linkage_name.data (), linkage_name.length ());
-         name[linkage_name.length ()] = '\0';
-         gsymbol->name = name;
-       }
-      symbol_set_demangled_name (gsymbol, NULL, &per_bfd->storage_obstack);
+       m_name = obstack_strndup (&per_bfd->storage_obstack,
+                                 linkage_name.data (),
+                                 linkage_name.length ());
+      set_demangled_name (NULL, &per_bfd->storage_obstack);
 
       return;
     }
@@ -858,15 +864,27 @@ symbol_set_names (struct general_symbol_info *gsymbol,
     create_demangled_names_hash (per_bfd);
 
   struct demangled_name_entry entry (linkage_name);
+  if (!hash.has_value ())
+    hash = hash_demangled_name_entry (&entry);
   slot = ((struct demangled_name_entry **)
-         htab_find_slot (per_bfd->demangled_names_hash.get (),
-                         &entry, INSERT));
+          htab_find_slot_with_hash (per_bfd->demangled_names_hash.get (),
+                                   &entry, *hash, INSERT));
+
+  /* The const_cast is safe because the only reason it is already
+     initialized is if we purposefully set it from a background
+     thread to avoid doing the work here.  However, it is still
+     allocated from the heap and needs to be freed by us, just
+     like if we called symbol_find_demangled_name here.  If this is
+     nullptr, we call symbol_find_demangled_name below, but we put
+     this smart pointer here to be sure that we don't leak this name.  */
+  gdb::unique_xmalloc_ptr<char> demangled_name
+    (const_cast<char *> (language_specific.demangled_name));
 
   /* If this name is not in the hash table, add it.  */
   if (*slot == NULL
       /* A C version of the symbol may have already snuck into the table.
         This happens to, e.g., main.init (__go_init_main).  Cope.  */
-      || (gsymbol->language == language_go && (*slot)->demangled == nullptr))
+      || (language () == language_go && (*slot)->demangled == nullptr))
     {
       /* A 0-terminated copy of the linkage name.  Callers must set COPY_NAME
          to true if the string might not be nullterminated.  We have to make
@@ -884,8 +902,9 @@ symbol_set_names (struct general_symbol_info *gsymbol,
       else
        linkage_name_copy = linkage_name;
 
-      gdb::unique_xmalloc_ptr<char> demangled_name_ptr
-       (symbol_find_demangled_name (gsymbol, linkage_name_copy.data ()));
+      if (demangled_name.get () == nullptr)
+        demangled_name.reset
+          (symbol_find_demangled_name (this, linkage_name_copy.data ()));
 
       /* Suppose we have demangled_name==NULL, copy_name==0, and
         linkage_name_copy==linkage_name.  In this case, we already have the
@@ -919,64 +938,59 @@ symbol_set_names (struct general_symbol_info *gsymbol,
          new (*slot) demangled_name_entry
            (gdb::string_view (mangled_ptr, linkage_name.length ()));
        }
-      (*slot)->demangled = std::move (demangled_name_ptr);
-      (*slot)->language = gsymbol->language;
+      (*slot)->demangled = std::move (demangled_name);
+      (*slot)->language = language ();
     }
-  else if (gsymbol->language == language_unknown
-          || gsymbol->language == language_auto)
-    gsymbol->language = (*slot)->language;
+  else if (language () == language_unknown || language () == language_auto)
+    m_language = (*slot)->language;
 
-  gsymbol->name = (*slot)->mangled.data ();
-  if ((*slot)->demangled != nullptr)
-    symbol_set_demangled_name (gsymbol, (*slot)->demangled.get (),
-                              &per_bfd->storage_obstack);
-  else
-    symbol_set_demangled_name (gsymbol, NULL, &per_bfd->storage_obstack);
+  m_name = (*slot)->mangled.data ();
+  set_demangled_name ((*slot)->demangled.get (), &per_bfd->storage_obstack);
 }
 
-/* Return the source code name of a symbol.  In languages where
-   demangling is necessary, this is the demangled name.  */
+/* See symtab.h.  */
 
 const char *
-symbol_natural_name (const struct general_symbol_info *gsymbol)
+general_symbol_info::natural_name () const
 {
-  switch (gsymbol->language)
+  switch (language ())
     {
     case language_cplus:
     case language_d:
     case language_go:
     case language_objc:
     case language_fortran:
-      if (symbol_get_demangled_name (gsymbol) != NULL)
-       return symbol_get_demangled_name (gsymbol);
+    case language_rust:
+      if (language_specific.demangled_name != nullptr)
+       return language_specific.demangled_name;
       break;
     case language_ada:
-      return ada_decode_symbol (gsymbol);
+      return ada_decode_symbol (this);
     default:
       break;
     }
-  return gsymbol->name;
+  return linkage_name ();
 }
 
-/* Return the demangled name for a symbol based on the language for
-   that symbol.  If no demangled name exists, return NULL.  */
+/* See symtab.h.  */
 
 const char *
-symbol_demangled_name (const struct general_symbol_info *gsymbol)
+general_symbol_info::demangled_name () const
 {
   const char *dem_name = NULL;
 
-  switch (gsymbol->language)
+  switch (language ())
     {
     case language_cplus:
     case language_d:
     case language_go:
     case language_objc:
     case language_fortran:
-      dem_name = symbol_get_demangled_name (gsymbol);
+    case language_rust:
+      dem_name = language_specific.demangled_name;
       break;
     case language_ada:
-      dem_name = ada_decode_symbol (gsymbol);
+      dem_name = ada_decode_symbol (this);
       break;
     default:
       break;
@@ -984,18 +998,15 @@ symbol_demangled_name (const struct general_symbol_info *gsymbol)
   return dem_name;
 }
 
-/* Return the search name of a symbol---generally the demangled or
-   linkage name of the symbol, depending on how it will be searched for.
-   If there is no distinct demangled name, then returns the same value
-   (same pointer) as SYMBOL_LINKAGE_NAME.  */
+/* See symtab.h.  */
 
 const char *
-symbol_search_name (const struct general_symbol_info *gsymbol)
+general_symbol_info::search_name () const
 {
-  if (gsymbol->language == language_ada)
-    return gsymbol->name;
+  if (language () == language_ada)
+    return linkage_name ();
   else
-    return symbol_natural_name (gsymbol);
+    return natural_name ();
 }
 
 /* See symtab.h.  */
@@ -1005,8 +1016,8 @@ symbol_matches_search_name (const struct general_symbol_info *gsymbol,
                            const lookup_name_info &name)
 {
   symbol_name_matcher_ftype *name_match
-    = get_symbol_name_matcher (language_def (gsymbol->language), name);
-  return name_match (symbol_search_name (gsymbol), name, NULL);
+    = get_symbol_name_matcher (language_def (gsymbol->language ()), name);
+  return name_match (gsymbol->search_name (), name, NULL);
 }
 
 \f
@@ -1146,7 +1157,7 @@ eq_symbol_entry (const struct symbol_cache_slot *slot,
     }
   else
     {
-      slot_name = SYMBOL_SEARCH_NAME (slot->value.found.symbol);
+      slot_name = slot->value.found.symbol->search_name ();
       slot_domain = SYMBOL_DOMAIN (slot->value.found.symbol);
     }
 
@@ -1163,7 +1174,7 @@ eq_symbol_entry (const struct symbol_cache_slot *slot,
       /* It's important that we use the same comparison that was done
         the first time through.  If the slot records a found symbol,
         then this means using the symbol name comparison function of
-        the symbol's language with SYMBOL_SEARCH_NAME.  See
+        the symbol's language with symbol->search_name ().  See
         dictionary.c.  It also means using symbol_matches_domain for
         found symbols.  See block.c.
 
@@ -1185,8 +1196,7 @@ eq_symbol_entry (const struct symbol_cache_slot *slot,
          if (!SYMBOL_MATCHES_SEARCH_NAME (sym, lookup_name))
            return 0;
 
-         if (!symbol_matches_domain (SYMBOL_LANGUAGE (sym),
-                                     slot_domain, domain))
+         if (!symbol_matches_domain (sym->language (), slot_domain, domain))
            return 0;
        }
     }
@@ -1223,8 +1233,8 @@ resize_symbol_cache (struct symbol_cache *cache, unsigned int new_size)
          && new_size == 0))
     return;
 
-  xfree (cache->global_symbols);
-  xfree (cache->static_symbols);
+  destroy_block_symbol_cache (cache->global_symbols);
+  destroy_block_symbol_cache (cache->static_symbols);
 
   if (new_size == 0)
     {
@@ -1266,9 +1276,7 @@ get_symbol_cache (struct program_space *pspace)
 static void
 set_symbol_cache_size (unsigned int new_size)
 {
-  struct program_space *pspace;
-
-  ALL_PSPACES (pspace)
+  for (struct program_space *pspace : program_spaces)
     {
       struct symbol_cache *cache = symbol_cache_key.get (pspace);
 
@@ -1362,16 +1370,6 @@ symbol_cache_lookup (struct symbol_cache *cache,
   return {};
 }
 
-/* Clear out SLOT.  */
-
-static void
-symbol_cache_clear_slot (struct symbol_cache_slot *slot)
-{
-  if (slot->state == SYMBOL_SLOT_NOT_FOUND)
-    xfree (slot->value.not_found.name);
-  slot->state = SYMBOL_SLOT_UNUSED;
-}
-
 /* Mark SYMBOL as found in SLOT.
    OBJFILE_CONTEXT is the current objfile when the lookup was done, or NULL
    if it's not needed to distinguish lookups (STATIC_BLOCK).  It is *not*
@@ -1512,7 +1510,7 @@ symbol_cache_dump (const struct symbol_cache *cache)
 
                printf_filtered ("  [%4u] = %s, %s %s\n", i,
                                 host_address_to_string (context),
-                                SYMBOL_PRINT_NAME (found),
+                                found->print_name (),
                                 domain_name (SYMBOL_DOMAIN (found)));
                break;
              }
@@ -1526,9 +1524,7 @@ symbol_cache_dump (const struct symbol_cache *cache)
 static void
 maintenance_print_symbol_cache (const char *args, int from_tty)
 {
-  struct program_space *pspace;
-
-  ALL_PSPACES (pspace)
+  for (struct program_space *pspace : program_spaces)
     {
       struct symbol_cache *cache;
 
@@ -1552,9 +1548,7 @@ maintenance_print_symbol_cache (const char *args, int from_tty)
 static void
 maintenance_flush_symbol_cache (const char *args, int from_tty)
 {
-  struct program_space *pspace;
-
-  ALL_PSPACES (pspace)
+  for (struct program_space *pspace : program_spaces)
     {
       symbol_cache_flush (pspace);
     }
@@ -1597,9 +1591,7 @@ symbol_cache_stats (struct symbol_cache *cache)
 static void
 maintenance_print_symbol_cache_statistics (const char *args, int from_tty)
 {
-  struct program_space *pspace;
-
-  ALL_PSPACES (pspace)
+  for (struct program_space *pspace : program_spaces)
     {
       struct symbol_cache *cache;
 
@@ -1649,7 +1641,8 @@ fixup_section (struct general_symbol_info *ginfo,
      e.g. on PowerPC64, where the minimal symbol for a function will
      point to the function descriptor, while the debug symbol will
      point to the actual function code.  */
-  msym = lookup_minimal_symbol_by_pc_name (addr, ginfo->name, objfile);
+  msym = lookup_minimal_symbol_by_pc_name (addr, ginfo->linkage_name (),
+                                          objfile);
   if (msym)
     ginfo->section = MSYMBOL_SECTION (msym);
   else
@@ -1666,11 +1659,10 @@ fixup_section (struct general_symbol_info *ginfo,
 
         So, instead, search the section table when lookup by name has
         failed.  The ``addr'' and ``endaddr'' fields may have already
-        been relocated.  If so, the relocation offset (i.e. the
-        ANOFFSET value) needs to be subtracted from these values when
-        performing the comparison.  We unconditionally subtract it,
-        because, when no relocation has been performed, the ANOFFSET
-        value will simply be zero.
+        been relocated.  If so, the relocation offset needs to be
+        subtracted from these values when performing the comparison.
+        We unconditionally subtract it, because, when no relocation
+        has been performed, the value will simply be zero.
 
         The address of the symbol whose section we're fixing up HAS
         NOT BEEN adjusted (relocated) yet.  It can't have been since
@@ -1696,7 +1688,7 @@ fixup_section (struct general_symbol_info *ginfo,
       ALL_OBJFILE_OSECTIONS (objfile, s)
        {
          int idx = s - objfile->sections;
-         CORE_ADDR offset = ANOFFSET (objfile->section_offsets, idx);
+         CORE_ADDR offset = objfile->section_offsets[idx];
 
          if (fallback == -1)
            fallback = idx;
@@ -1759,7 +1751,7 @@ fixup_symbol_section (struct symbol *sym, struct objfile *objfile)
       return sym;
     }
 
-  fixup_section (&sym->ginfo, addr, objfile);
+  fixup_section (sym, addr, objfile);
 
   return sym;
 }
@@ -1774,7 +1766,7 @@ demangle_for_lookup_info::demangle_for_lookup_info
   if (lookup_name.ignore_parameters () && lang == language_cplus)
     {
       gdb::unique_xmalloc_ptr<char> without_params
-       = cp_remove_params_if_any (lookup_name.name ().c_str (),
+       = cp_remove_params_if_any (lookup_name.c_str (),
                                   lookup_name.completion_mode ());
 
       if (without_params != NULL)
@@ -1787,9 +1779,9 @@ demangle_for_lookup_info::demangle_for_lookup_info
     }
 
   if (lookup_name.match_type () == symbol_name_match_type::SEARCH_NAME)
-    m_demangled_name = lookup_name.name ();
+    m_demangled_name = lookup_name.c_str ();
   else
-    m_demangled_name = demangle_for_lookup (lookup_name.name ().c_str (),
+    m_demangled_name = demangle_for_lookup (lookup_name.c_str (),
                                            lang, storage);
 }
 
@@ -1800,7 +1792,7 @@ lookup_name_info::match_any ()
 {
   /* Lookup any symbol that "" would complete.  I.e., this matches all
      symbol names.  */
-  static const lookup_name_info lookup_name ({}, symbol_name_match_type::FULL,
+  static const lookup_name_info lookup_name ("", symbol_name_match_type::FULL,
                                             true);
 
   return lookup_name;
@@ -1838,9 +1830,9 @@ demangle_for_lookup (const char *name, enum language lang,
 
       /* If we were given a non-mangled name, canonicalize it
         according to the language (so far only for C++).  */
-      std::string canon = cp_canonicalize_string (name);
-      if (!canon.empty ())
-       return storage.swap_string (canon);
+      gdb::unique_xmalloc_ptr<char> canon = cp_canonicalize_string (name);
+      if (canon != nullptr)
+       return storage.set_malloc_ptr (std::move (canon));
     }
   else if (lang == language_d)
     {
@@ -1863,7 +1855,7 @@ demangle_for_lookup (const char *name, enum language lang,
 unsigned int
 search_name_hash (enum language language, const char *search_name)
 {
-  return language_def (language)->la_search_name_hash (search_name);
+  return language_def (language)->search_name_hash (search_name);
 }
 
 /* See symtab.h.
@@ -1925,7 +1917,7 @@ lookup_language_this (const struct language_defn *lang,
 
   if (symbol_lookup_debug > 1)
     {
-      struct objfile *objfile = lookup_objfile_from_block (block);
+      struct objfile *objfile = block_objfile (block);
 
       fprintf_unfiltered (gdb_stdlog,
                          "lookup_language_this (%s, %s (objfile %s))",
@@ -1945,7 +1937,7 @@ lookup_language_this (const struct language_defn *lang,
          if (symbol_lookup_debug > 1)
            {
              fprintf_unfiltered (gdb_stdlog, " = %s (%s, block %s)\n",
-                                 SYMBOL_PRINT_NAME (sym),
+                                 sym->print_name (),
                                  host_address_to_string (sym),
                                  host_address_to_string (block));
            }
@@ -1974,14 +1966,14 @@ check_field (struct type *type, const char *name,
   /* The type may be a stub.  */
   type = check_typedef (type);
 
-  for (i = TYPE_NFIELDS (type) - 1; i >= TYPE_N_BASECLASSES (type); i--)
+  for (i = type->num_fields () - 1; i >= TYPE_N_BASECLASSES (type); i--)
     {
       const char *t_field_name = TYPE_FIELD_NAME (type, i);
 
       if (t_field_name && (strcmp_iw (t_field_name, name) == 0))
        {
          is_a_field_of_this->type = type;
-         is_a_field_of_this->field = &TYPE_FIELD (type, i);
+         is_a_field_of_this->field = &type->field (i);
          return 1;
        }
     }
@@ -2020,7 +2012,8 @@ lookup_symbol_aux (const char *name, symbol_name_match_type match_type,
 
   if (symbol_lookup_debug)
     {
-      struct objfile *objfile = lookup_objfile_from_block (block);
+      struct objfile *objfile = (block == nullptr
+                                ? nullptr : block_objfile (block));
 
       fprintf_unfiltered (gdb_stdlog,
                          "lookup_symbol_aux (%s, %s (objfile %s), %s, %s)\n",
@@ -2070,11 +2063,11 @@ lookup_symbol_aux (const char *name, symbol_name_match_type match_type,
          /* I'm not really sure that type of this can ever
             be typedefed; just be safe.  */
          t = check_typedef (t);
-         if (TYPE_CODE (t) == TYPE_CODE_PTR || TYPE_IS_REFERENCE (t))
+         if (t->code () == TYPE_CODE_PTR || TYPE_IS_REFERENCE (t))
            t = TYPE_TARGET_TYPE (t);
 
-         if (TYPE_CODE (t) != TYPE_CODE_STRUCT
-             && TYPE_CODE (t) != TYPE_CODE_UNION)
+         if (t->code () != TYPE_CODE_STRUCT
+             && t->code () != TYPE_CODE_UNION)
            error (_("Internal error: `%s' is not an aggregate"),
                   langdef->la_name_of_this);
 
@@ -2165,32 +2158,6 @@ lookup_local_symbol (const char *name,
 
 /* See symtab.h.  */
 
-struct objfile *
-lookup_objfile_from_block (const struct block *block)
-{
-  if (block == NULL)
-    return NULL;
-
-  block = block_global_block (block);
-  /* Look through all blockvectors.  */
-  for (objfile *obj : current_program_space->objfiles ())
-    {
-      for (compunit_symtab *cust : obj->compunits ())
-       if (block == BLOCKVECTOR_BLOCK (COMPUNIT_BLOCKVECTOR (cust),
-                                       GLOBAL_BLOCK))
-         {
-           if (obj->separate_debug_objfile_backlink)
-             obj = obj->separate_debug_objfile_backlink;
-
-           return obj;
-         }
-    }
-
-  return NULL;
-}
-
-/* See symtab.h.  */
-
 struct symbol *
 lookup_symbol_in_block (const char *name, symbol_name_match_type match_type,
                        const struct block *block,
@@ -2200,7 +2167,8 @@ lookup_symbol_in_block (const char *name, symbol_name_match_type match_type,
 
   if (symbol_lookup_debug > 1)
     {
-      struct objfile *objfile = lookup_objfile_from_block (block);
+      struct objfile *objfile = (block == nullptr
+                                ? nullptr : block_objfile (block));
 
       fprintf_unfiltered (gdb_stdlog,
                          "lookup_symbol_in_block (%s, %s (objfile %s), %s)",
@@ -2269,6 +2237,8 @@ lookup_symbol_in_objfile_symtabs (struct objfile *objfile,
                          name, domain_name (domain));
     }
 
+  struct block_symbol other;
+  other.symbol = NULL;
   for (compunit_symtab *cust : objfile->compunits ())
     {
       const struct blockvector *bv;
@@ -2279,18 +2249,36 @@ lookup_symbol_in_objfile_symtabs (struct objfile *objfile,
       block = BLOCKVECTOR_BLOCK (bv, block_index);
       result.symbol = block_lookup_symbol_primary (block, name, domain);
       result.block = block;
-      if (result.symbol != NULL)
+      if (result.symbol == NULL)
+       continue;
+      if (best_symbol (result.symbol, domain))
        {
-         if (symbol_lookup_debug > 1)
+         other = result;
+         break;
+       }
+      if (symbol_matches_domain (result.symbol->language (),
+                                SYMBOL_DOMAIN (result.symbol), domain))
+       {
+         struct symbol *better
+           = better_symbol (other.symbol, result.symbol, domain);
+         if (better != other.symbol)
            {
-             fprintf_unfiltered (gdb_stdlog, " = %s (block %s)\n",
-                                 host_address_to_string (result.symbol),
-                                 host_address_to_string (block));
+             other.symbol = better;
+             other.block = block;
            }
-         result.symbol = fixup_symbol_section (result.symbol, objfile);
-         return result;
+       }
+    }
 
+  if (other.symbol != NULL)
+    {
+      if (symbol_lookup_debug > 1)
+       {
+         fprintf_unfiltered (gdb_stdlog, " = %s (block %s)\n",
+                             host_address_to_string (other.symbol),
+                             host_address_to_string (other.block));
        }
+      other.symbol = fixup_symbol_section (other.symbol, objfile);
+      return other;
     }
 
   if (symbol_lookup_debug > 1)
@@ -2470,7 +2458,8 @@ lookup_symbol_in_static_block (const char *name,
 
   if (symbol_lookup_debug)
     {
-      struct objfile *objfile = lookup_objfile_from_block (static_block);
+      struct objfile *objfile = (block == nullptr
+                                ? nullptr : block_objfile (block));
 
       fprintf_unfiltered (gdb_stdlog,
                          "lookup_symbol_in_static_block (%s, %s (objfile %s),"
@@ -2544,6 +2533,33 @@ lookup_symbol_in_objfile (struct objfile *objfile, enum block_enum block_index,
   return result;
 }
 
+/* Find the language for partial symbol with NAME.  */
+
+static enum language
+find_quick_global_symbol_language (const char *name, const domain_enum domain)
+{
+  for (objfile *objfile : current_program_space->objfiles ())
+    {
+      if (objfile->sf && objfile->sf->qf
+         && objfile->sf->qf->lookup_global_symbol_language)
+       continue;
+      return language_unknown;
+    }
+
+  for (objfile *objfile : current_program_space->objfiles ())
+    {
+      bool symbol_found_p;
+      enum language lang
+       = objfile->sf->qf->lookup_global_symbol_language (objfile, name, domain,
+                                                         &symbol_found_p);
+      if (!symbol_found_p)
+       continue;
+      return lang;
+    }
+
+  return language_unknown;
+}
+
 /* Private data to be used with lookup_symbol_global_iterator_cb.  */
 
 struct global_or_static_sym_lookup_data
@@ -2623,7 +2639,7 @@ lookup_global_or_static_symbol (const char *name,
       lookup_data.block_index = block_index;
       lookup_data.domain = domain;
       gdbarch_iterate_over_objfiles_in_search_order
-       (objfile != NULL ? get_objfile_arch (objfile) : target_gdbarch (),
+       (objfile != NULL ? objfile->arch () : target_gdbarch (),
         lookup_symbol_global_or_static_iterator_cb, &lookup_data, objfile);
       result = lookup_data.result;
     }
@@ -2655,17 +2671,30 @@ lookup_global_symbol (const char *name,
      global block first.  This yields "more expected" behavior, and is
      needed to support 'FILENAME'::VARIABLE lookups.  */
   const struct block *global_block = block_global_block (block);
+  symbol *sym = NULL;
   if (global_block != nullptr)
     {
-      symbol *sym = lookup_symbol_in_block (name,
-                                           symbol_name_match_type::FULL,
-                                           global_block, domain);
-      if (sym != nullptr)
+      sym = lookup_symbol_in_block (name,
+                                   symbol_name_match_type::FULL,
+                                   global_block, domain);
+      if (sym != NULL && best_symbol (sym, domain))
        return { sym, global_block };
     }
 
-  struct objfile *objfile = lookup_objfile_from_block (block);
-  return lookup_global_or_static_symbol (name, GLOBAL_BLOCK, objfile, domain);
+  struct objfile *objfile = nullptr;
+  if (block != nullptr)
+    {
+      objfile = block_objfile (block);
+      if (objfile->separate_debug_objfile_backlink != nullptr)
+       objfile = objfile->separate_debug_objfile_backlink;
+    }
+
+  block_symbol bs
+    = lookup_global_or_static_symbol (name, GLOBAL_BLOCK, objfile, domain);
+  if (better_symbol (sym, bs.symbol, domain) == sym)
+    return { sym, global_block };
+  else
+    return bs;
 }
 
 bool
@@ -2693,7 +2722,7 @@ symbol_matches_domain (enum language symbol_language,
 struct type *
 lookup_transparent_type (const char *name)
 {
-  return current_language->la_lookup_transparent_type (name);
+  return current_language->lookup_transparent_type (name);
 }
 
 /* A helper for basic_lookup_transparent_type that interfaces with the
@@ -2822,8 +2851,7 @@ iterate_over_symbols (const struct block *block,
 
   ALL_BLOCK_SYMBOLS_WITH_NAME (block, name, iter, sym)
     {
-      if (symbol_matches_domain (SYMBOL_LANGUAGE (sym),
-                                SYMBOL_DOMAIN (sym), domain))
+      if (symbol_matches_domain (sym->language (), SYMBOL_DOMAIN (sym), domain))
        {
          struct block_symbol block_sym = {sym, block};
 
@@ -3117,7 +3145,7 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
     if (MSYMBOL_TYPE (msymbol.minsym) == mst_solib_trampoline)
       {
        struct bound_minimal_symbol mfunsym
-         = lookup_minimal_symbol_text (MSYMBOL_LINKAGE_NAME (msymbol.minsym),
+         = lookup_minimal_symbol_text (msymbol.minsym->linkage_name (),
                                        NULL);
 
        if (mfunsym.minsym == NULL)
@@ -3131,7 +3159,7 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
           * but the "break" still works, and the warning is annoying.
           * So I commented out the warning.  RT */
          /* warning ("In stub for %s; unable to find real function/line info",
-            SYMBOL_LINKAGE_NAME (msymbol)); */
+            msymbol->linkage_name ()); */
          ;
        /* fall through */
        else if (BMSYMBOL_VALUE_ADDRESS (mfunsym)
@@ -3139,11 +3167,21 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
          /* Avoid infinite recursion */
          /* See above comment about why warning is commented out.  */
          /* warning ("In stub for %s; unable to find real function/line info",
-            SYMBOL_LINKAGE_NAME (msymbol)); */
+            msymbol->linkage_name ()); */
          ;
        /* fall through */
        else
-         return find_pc_line (BMSYMBOL_VALUE_ADDRESS (mfunsym), 0);
+         {
+           /* Detect an obvious case of infinite recursion.  If this
+              should occur, we'd like to know about it, so error out,
+              fatally.  */
+           if (BMSYMBOL_VALUE_ADDRESS (mfunsym) == pc)
+             internal_error (__FILE__, __LINE__,
+               _("Infinite recursion detected in find_pc_sect_line;"
+                 "please file a bug report"));
+
+           return find_pc_line (BMSYMBOL_VALUE_ADDRESS (mfunsym), 0);
+         }
       }
 
   symtab_and_line val;
@@ -3199,7 +3237,12 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
       struct linetable_entry *last = item + len;
       item = std::upper_bound (first, last, pc, pc_compare);
       if (item != first)
-       prev = item - 1;                /* Found a matching item.  */
+       {
+         /* Found a matching item.  Skip backwards over any end of
+            sequence markers.  */
+         for (prev = item - 1; prev->line == 0 && prev != first; prev--)
+           /* Nothing.  */;
+       }
 
       /* At this point, prev points at the line whose start addr is <= pc, and
          item points at the next line.  If we ran off the end of the linetable
@@ -3216,6 +3259,23 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
          best = prev;
          best_symtab = iter_s;
 
+         /* If during the binary search we land on a non-statement entry,
+            scan backward through entries at the same address to see if
+            there is an entry marked as is-statement.  In theory this
+            duplication should have been removed from the line table
+            during construction, this is just a double check.  If the line
+            table has had the duplication removed then this should be
+            pretty cheap.  */
+         if (!best->is_stmt)
+           {
+             struct linetable_entry *tmp = best;
+             while (tmp > first && (tmp - 1)->pc == tmp->pc
+                    && (tmp - 1)->line != 0 && !tmp->is_stmt)
+               --tmp;
+             if (tmp->is_stmt)
+               best = tmp;
+           }
+
          /* Discard BEST_END if it's before the PC of the current BEST.  */
          if (best_end <= best->pc)
            best_end = 0;
@@ -3246,6 +3306,7 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
     }
   else
     {
+      val.is_stmt = best->is_stmt;
       val.symtab = best_symtab;
       val.line = best->line;
       val.pc = best->pc;
@@ -3414,7 +3475,8 @@ find_pcs_for_symtab_line (struct symtab *symtab, int line,
        {
          struct linetable_entry *item = &SYMTAB_LINETABLE (symtab)->item[idx];
 
-         if (*best_item == NULL || item->line < (*best_item)->line)
+         if (*best_item == NULL
+             || (item->line < (*best_item)->line && item->is_stmt))
            *best_item = item;
 
          break;
@@ -3525,6 +3587,10 @@ find_line_common (struct linetable *l, int lineno,
     {
       struct linetable_entry *item = &(l->item[i]);
 
+      /* Ignore non-statements.  */
+      if (!item->is_stmt)
+       continue;
+
       if (item->line == lineno)
        {
          /* Return the first (lowest address) entry which matches.  */
@@ -3567,7 +3633,7 @@ find_function_start_sal_1 (CORE_ADDR func_addr, obj_section *section,
       && (COMPUNIT_LOCATIONS_VALID (SYMTAB_COMPUNIT (sal.symtab))
          || SYMTAB_LANGUAGE (sal.symtab) == language_asm))
     {
-      struct gdbarch *gdbarch = get_objfile_arch (SYMTAB_OBJFILE (sal.symtab));
+      struct gdbarch *gdbarch = SYMTAB_OBJFILE (sal.symtab)->arch ();
 
       sal.pc = func_addr;
       if (gdbarch_skip_entrypoint_p (gdbarch))
@@ -3710,7 +3776,7 @@ skip_prologue_sal (struct symtab_and_line *sal)
       objfile = symbol_objfile (sym);
       pc = BLOCK_ENTRY_PC (SYMBOL_BLOCK_VALUE (sym));
       section = SYMBOL_OBJ_SECTION (objfile, sym);
-      name = SYMBOL_LINKAGE_NAME (sym);
+      name = sym->linkage_name ();
     }
   else
     {
@@ -3723,10 +3789,10 @@ skip_prologue_sal (struct symtab_and_line *sal)
       objfile = msymbol.objfile;
       pc = BMSYMBOL_VALUE_ADDRESS (msymbol);
       section = MSYMBOL_OBJ_SECTION (objfile, msymbol.minsym);
-      name = MSYMBOL_LINKAGE_NAME (msymbol.minsym);
+      name = msymbol.minsym->linkage_name ();
     }
 
-  gdbarch = get_objfile_arch (objfile);
+  gdbarch = objfile->arch ();
 
   /* Process the prologue in two passes.  In the first pass try to skip the
      prologue (SKIP is true) and verify there is a real need for it (indicated
@@ -4339,31 +4405,28 @@ info_sources_command (const char *args, int from_tty)
   printf_filtered ("\n");
 }
 
-/* Compare FILE against all the NFILES entries of FILES.  If BASENAMES is
-   non-zero compare only lbasename of FILES.  */
+/* Compare FILE against all the entries of FILENAMES.  If BASENAMES is
+   true compare only lbasename of FILENAMES.  */
 
-static int
-file_matches (const char *file, const char *files[], int nfiles, int basenames)
+static bool
+file_matches (const char *file, const std::vector<const char *> &filenames,
+             bool basenames)
 {
-  int i;
+  if (filenames.empty ())
+    return true;
 
-  if (file != NULL && nfiles != 0)
+  for (const char *name : filenames)
     {
-      for (i = 0; i < nfiles; i++)
-       {
-         if (compare_filenames_for_search (file, (basenames
-                                                  ? lbasename (files[i])
-                                                  : files[i])))
-           return 1;
-       }
+      name = (basenames ? lbasename (name) : name);
+      if (compare_filenames_for_search (file, name))
+       return true;
     }
-  else if (nfiles == 0)
-    return 1;
-  return 0;
+
+  return false;
 }
 
-/* Helper function for sort_search_symbols_remove_dups and qsort.  Can only
-   sort symbols, not minimal symbols.  */
+/* Helper function for std::sort on symbol_search objects.  Can only sort
+   symbols, not minimal symbols.  */
 
 int
 symbol_search::compare_search_syms (const symbol_search &sym_a,
@@ -4379,8 +4442,7 @@ symbol_search::compare_search_syms (const symbol_search &sym_a,
   if (sym_a.block != sym_b.block)
     return sym_a.block - sym_b.block;
 
-  return strcmp (SYMBOL_PRINT_NAME (sym_a.symbol),
-                SYMBOL_PRINT_NAME (sym_b.symbol));
+  return strcmp (sym_a.symbol->print_name (), sym_b.symbol->print_name ());
 }
 
 /* Returns true if the type_name of symbol_type of SYM matches TREG.
@@ -4397,7 +4459,7 @@ treg_matches_sym_type_name (const compiled_regex &treg,
     {
       fprintf_unfiltered (gdb_stdlog,
                          "treg_matches_sym_type_name\n     sym %s\n",
-                         SYMBOL_NATURAL_NAME (sym));
+                         sym->natural_name ());
     }
 
   sym_type = SYMBOL_TYPE (sym);
@@ -4425,79 +4487,255 @@ treg_matches_sym_type_name (const compiled_regex &treg,
   return treg.exec (printed_sym_type_name.c_str (), 0, NULL, 0) == 0;
 }
 
+/* See symtab.h.  */
+
+bool
+global_symbol_searcher::is_suitable_msymbol
+       (const enum search_domain kind, const minimal_symbol *msymbol)
+{
+  switch (MSYMBOL_TYPE (msymbol))
+    {
+    case mst_data:
+    case mst_bss:
+    case mst_file_data:
+    case mst_file_bss:
+      return kind == VARIABLES_DOMAIN;
+    case mst_text:
+    case mst_file_text:
+    case mst_solib_trampoline:
+    case mst_text_gnu_ifunc:
+      return kind == FUNCTIONS_DOMAIN;
+    default:
+      return false;
+    }
+}
+
+/* See symtab.h.  */
 
-/* Sort the symbols in RESULT and remove duplicates.  */
+bool
+global_symbol_searcher::expand_symtabs
+       (objfile *objfile, const gdb::optional<compiled_regex> &preg) const
+{
+  enum search_domain kind = m_kind;
+  bool found_msymbol = false;
+
+  if (objfile->sf)
+    objfile->sf->qf->expand_symtabs_matching
+      (objfile,
+       [&] (const char *filename, bool basenames)
+       {
+        return file_matches (filename, filenames, basenames);
+       },
+       &lookup_name_info::match_any (),
+       [&] (const char *symname)
+       {
+        return (!preg.has_value ()
+                || preg->exec (symname, 0, NULL, 0) == 0);
+       },
+       NULL,
+       kind);
+
+  /* Here, we search through the minimal symbol tables for functions and
+     variables that match, and force their symbols to be read.  This is in
+     particular necessary for demangled variable names, which are no longer
+     put into the partial symbol tables.  The symbol will then be found
+     during the scan of symtabs later.
+
+     For functions, find_pc_symtab should succeed if we have debug info for
+     the function, for variables we have to call
+     lookup_symbol_in_objfile_from_linkage_name to determine if the
+     variable has debug info.  If the lookup fails, set found_msymbol so
+     that we will rescan to print any matching symbols without debug info.
+     We only search the objfile the msymbol came from, we no longer search
+     all objfiles.  In large programs (1000s of shared libs) searching all
+     objfiles is not worth the pain.  */
+  if (filenames.empty ()
+      && (kind == VARIABLES_DOMAIN || kind == FUNCTIONS_DOMAIN))
+    {
+      for (minimal_symbol *msymbol : objfile->msymbols ())
+       {
+         QUIT;
 
-static void
-sort_search_symbols_remove_dups (std::vector<symbol_search> *result)
+         if (msymbol->created_by_gdb)
+           continue;
+
+         if (is_suitable_msymbol (kind, msymbol))
+           {
+             if (!preg.has_value ()
+                 || preg->exec (msymbol->natural_name (), 0,
+                                NULL, 0) == 0)
+               {
+                 /* An important side-effect of these lookup functions is
+                    to expand the symbol table if msymbol is found, later
+                    in the process we will add matching symbols or
+                    msymbols to the results list, and that requires that
+                    the symbols tables are expanded.  */
+                 if (kind == FUNCTIONS_DOMAIN
+                     ? (find_pc_compunit_symtab
+                        (MSYMBOL_VALUE_ADDRESS (objfile, msymbol))
+                        == NULL)
+                     : (lookup_symbol_in_objfile_from_linkage_name
+                        (objfile, msymbol->linkage_name (),
+                         VAR_DOMAIN)
+                        .symbol == NULL))
+                   found_msymbol = true;
+               }
+           }
+       }
+    }
+
+  return found_msymbol;
+}
+
+/* See symtab.h.  */
+
+bool
+global_symbol_searcher::add_matching_symbols
+       (objfile *objfile,
+        const gdb::optional<compiled_regex> &preg,
+        const gdb::optional<compiled_regex> &treg,
+        std::set<symbol_search> *result_set) const
 {
-  std::sort (result->begin (), result->end ());
-  result->erase (std::unique (result->begin (), result->end ()),
-                result->end ());
+  enum search_domain kind = m_kind;
+
+  /* Add matching symbols (if not already present).  */
+  for (compunit_symtab *cust : objfile->compunits ())
+    {
+      const struct blockvector *bv  = COMPUNIT_BLOCKVECTOR (cust);
+
+      for (block_enum block : { GLOBAL_BLOCK, STATIC_BLOCK })
+       {
+         struct block_iterator iter;
+         struct symbol *sym;
+         const struct block *b = BLOCKVECTOR_BLOCK (bv, block);
+
+         ALL_BLOCK_SYMBOLS (b, iter, sym)
+           {
+             struct symtab *real_symtab = symbol_symtab (sym);
+
+             QUIT;
+
+             /* Check first sole REAL_SYMTAB->FILENAME.  It does
+                not need to be a substring of symtab_to_fullname as
+                it may contain "./" etc.  */
+             if ((file_matches (real_symtab->filename, filenames, false)
+                  || ((basenames_may_differ
+                       || file_matches (lbasename (real_symtab->filename),
+                                        filenames, true))
+                      && file_matches (symtab_to_fullname (real_symtab),
+                                       filenames, false)))
+                 && ((!preg.has_value ()
+                      || preg->exec (sym->natural_name (), 0,
+                                     NULL, 0) == 0)
+                     && ((kind == VARIABLES_DOMAIN
+                          && SYMBOL_CLASS (sym) != LOC_TYPEDEF
+                          && SYMBOL_CLASS (sym) != LOC_UNRESOLVED
+                          && SYMBOL_CLASS (sym) != LOC_BLOCK
+                          /* LOC_CONST can be used for more than
+                             just enums, e.g., c++ static const
+                             members.  We only want to skip enums
+                             here.  */
+                          && !(SYMBOL_CLASS (sym) == LOC_CONST
+                               && (SYMBOL_TYPE (sym)->code ()
+                                   == TYPE_CODE_ENUM))
+                          && (!treg.has_value ()
+                              || treg_matches_sym_type_name (*treg, sym)))
+                         || (kind == FUNCTIONS_DOMAIN
+                             && SYMBOL_CLASS (sym) == LOC_BLOCK
+                             && (!treg.has_value ()
+                                 || treg_matches_sym_type_name (*treg,
+                                                                sym)))
+                         || (kind == TYPES_DOMAIN
+                             && SYMBOL_CLASS (sym) == LOC_TYPEDEF
+                             && SYMBOL_DOMAIN (sym) != MODULE_DOMAIN)
+                         || (kind == MODULES_DOMAIN
+                             && SYMBOL_DOMAIN (sym) == MODULE_DOMAIN
+                             && SYMBOL_LINE (sym) != 0))))
+               {
+                 if (result_set->size () < m_max_search_results)
+                   {
+                     /* Match, insert if not already in the results.  */
+                     symbol_search ss (block, sym);
+                     if (result_set->find (ss) == result_set->end ())
+                       result_set->insert (ss);
+                   }
+                 else
+                   return false;
+               }
+           }
+       }
+    }
+
+  return true;
 }
 
-/* Search the symbol table for matches to the regular expression REGEXP,
-   returning the results.
+/* See symtab.h.  */
+
+bool
+global_symbol_searcher::add_matching_msymbols
+       (objfile *objfile, const gdb::optional<compiled_regex> &preg,
+        std::vector<symbol_search> *results) const
+{
+  enum search_domain kind = m_kind;
 
-   Only symbols of KIND are searched:
-   VARIABLES_DOMAIN - search all symbols, excluding functions, type names,
-                      and constants (enums).
-                     if T_REGEXP is not NULL, only returns var that have
-                     a type matching regular expression T_REGEXP.
-   FUNCTIONS_DOMAIN - search all functions
-   TYPES_DOMAIN     - search all type names
-   ALL_DOMAIN       - an internal error for this function
+  for (minimal_symbol *msymbol : objfile->msymbols ())
+    {
+      QUIT;
+
+      if (msymbol->created_by_gdb)
+       continue;
+
+      if (is_suitable_msymbol (kind, msymbol))
+       {
+         if (!preg.has_value ()
+             || preg->exec (msymbol->natural_name (), 0,
+                            NULL, 0) == 0)
+           {
+             /* For functions we can do a quick check of whether the
+                symbol might be found via find_pc_symtab.  */
+             if (kind != FUNCTIONS_DOMAIN
+                 || (find_pc_compunit_symtab
+                     (MSYMBOL_VALUE_ADDRESS (objfile, msymbol))
+                     == NULL))
+               {
+                 if (lookup_symbol_in_objfile_from_linkage_name
+                     (objfile, msymbol->linkage_name (),
+                      VAR_DOMAIN).symbol == NULL)
+                   {
+                     /* Matching msymbol, add it to the results list.  */
+                     if (results->size () < m_max_search_results)
+                       results->emplace_back (GLOBAL_BLOCK, msymbol, objfile);
+                     else
+                       return false;
+                   }
+               }
+           }
+       }
+    }
 
-   Within each file the results are sorted locally; each symtab's global and
-   static blocks are separately alphabetized.
-   Duplicate entries are removed.
+  return true;
+}
 
-   When EXCLUDE_MINSYMS is false then matching minsyms are also returned,
-   otherwise they are excluded.  */
+/* See symtab.h.  */
 
 std::vector<symbol_search>
-search_symbols (const char *regexp, enum search_domain kind,
-               const char *t_regexp,
-               int nfiles, const char *files[],
-               bool exclude_minsyms)
+global_symbol_searcher::search () const
 {
-  const struct blockvector *bv;
-  const struct block *b;
-  int i = 0;
-  struct block_iterator iter;
-  struct symbol *sym;
-  int found_misc = 0;
-  static const enum minimal_symbol_type types[]
-    = {mst_data, mst_text, mst_unknown};
-  static const enum minimal_symbol_type types2[]
-    = {mst_bss, mst_file_text, mst_unknown};
-  static const enum minimal_symbol_type types3[]
-    = {mst_file_data, mst_solib_trampoline, mst_unknown};
-  static const enum minimal_symbol_type types4[]
-    = {mst_file_bss, mst_text_gnu_ifunc, mst_unknown};
-  enum minimal_symbol_type ourtype;
-  enum minimal_symbol_type ourtype2;
-  enum minimal_symbol_type ourtype3;
-  enum minimal_symbol_type ourtype4;
-  std::vector<symbol_search> result;
   gdb::optional<compiled_regex> preg;
   gdb::optional<compiled_regex> treg;
 
-  gdb_assert (kind != ALL_DOMAIN);
-
-  ourtype = types[kind];
-  ourtype2 = types2[kind];
-  ourtype3 = types3[kind];
-  ourtype4 = types4[kind];
+  gdb_assert (m_kind != ALL_DOMAIN);
 
-  if (regexp != NULL)
+  if (m_symbol_name_regexp != NULL)
     {
+      const char *symbol_name_regexp = m_symbol_name_regexp;
+
       /* Make sure spacing is right for C++ operators.
          This is just a courtesy to make the matching less sensitive
          to how many spaces the user leaves between 'operator'
          and <TYPENAME> or <OPERATOR>.  */
       const char *opend;
-      const char *opname = operator_chars (regexp, &opend);
+      const char *opname = operator_chars (symbol_name_regexp, &opend);
 
       if (*opname)
        {
@@ -4522,247 +4760,80 @@ search_symbols (const char *regexp, enum search_domain kind,
              char *tmp = (char *) alloca (8 + fix + strlen (opname) + 1);
 
              sprintf (tmp, "operator%.*s%s", fix, " ", opname);
-             regexp = tmp;
+             symbol_name_regexp = tmp;
            }
        }
 
       int cflags = REG_NOSUB | (case_sensitivity == case_sensitive_off
                                ? REG_ICASE : 0);
-      preg.emplace (regexp, cflags, _("Invalid regexp"));
+      preg.emplace (symbol_name_regexp, cflags,
+                   _("Invalid regexp"));
     }
 
-  if (t_regexp != NULL)
+  if (m_symbol_type_regexp != NULL)
     {
       int cflags = REG_NOSUB | (case_sensitivity == case_sensitive_off
                                ? REG_ICASE : 0);
-      treg.emplace (t_regexp, cflags, _("Invalid regexp"));
-    }
-
-  /* Search through the partial symtabs *first* for all symbols
-     matching the regexp.  That way we don't have to reproduce all of
-     the machinery below.  */
-  expand_symtabs_matching ([&] (const char *filename, bool basenames)
-                          {
-                            return file_matches (filename, files, nfiles,
-                                                 basenames);
-                          },
-                          lookup_name_info::match_any (),
-                          [&] (const char *symname)
-                          {
-                            return (!preg.has_value ()
-                                    || preg->exec (symname,
-                                                   0, NULL, 0) == 0);
-                          },
-                          NULL,
-                          kind);
-
-  /* Here, we search through the minimal symbol tables for functions
-     and variables that match, and force their symbols to be read.
-     This is in particular necessary for demangled variable names,
-     which are no longer put into the partial symbol tables.
-     The symbol will then be found during the scan of symtabs below.
-
-     For functions, find_pc_symtab should succeed if we have debug info
-     for the function, for variables we have to call
-     lookup_symbol_in_objfile_from_linkage_name to determine if the variable
-     has debug info.
-     If the lookup fails, set found_misc so that we will rescan to print
-     any matching symbols without debug info.
-     We only search the objfile the msymbol came from, we no longer search
-     all objfiles.  In large programs (1000s of shared libs) searching all
-     objfiles is not worth the pain.  */
-
-  if (nfiles == 0 && (kind == VARIABLES_DOMAIN || kind == FUNCTIONS_DOMAIN))
-    {
-      for (objfile *objfile : current_program_space->objfiles ())
-       {
-         for (minimal_symbol *msymbol : objfile->msymbols ())
-           {
-             QUIT;
-
-             if (msymbol->created_by_gdb)
-               continue;
-
-             if (MSYMBOL_TYPE (msymbol) == ourtype
-                 || MSYMBOL_TYPE (msymbol) == ourtype2
-                 || MSYMBOL_TYPE (msymbol) == ourtype3
-                 || MSYMBOL_TYPE (msymbol) == ourtype4)
-               {
-                 if (!preg.has_value ()
-                     || preg->exec (MSYMBOL_NATURAL_NAME (msymbol), 0,
-                                    NULL, 0) == 0)
-                   {
-                     /* Note: An important side-effect of these
-                        lookup functions is to expand the symbol
-                        table if msymbol is found, for the benefit of
-                        the next loop on compunits.  */
-                     if (kind == FUNCTIONS_DOMAIN
-                         ? (find_pc_compunit_symtab
-                            (MSYMBOL_VALUE_ADDRESS (objfile, msymbol))
-                            == NULL)
-                         : (lookup_symbol_in_objfile_from_linkage_name
-                            (objfile, MSYMBOL_LINKAGE_NAME (msymbol),
-                             VAR_DOMAIN)
-                            .symbol == NULL))
-                       found_misc = 1;
-                   }
-               }
-           }
-       }
+      treg.emplace (m_symbol_type_regexp, cflags,
+                   _("Invalid regexp"));
     }
 
+  bool found_msymbol = false;
+  std::set<symbol_search> result_set;
   for (objfile *objfile : current_program_space->objfiles ())
     {
-      for (compunit_symtab *cust : objfile->compunits ())
-       {
-         bv = COMPUNIT_BLOCKVECTOR (cust);
-         for (i = GLOBAL_BLOCK; i <= STATIC_BLOCK; i++)
-           {
-             b = BLOCKVECTOR_BLOCK (bv, i);
-             ALL_BLOCK_SYMBOLS (b, iter, sym)
-               {
-                 struct symtab *real_symtab = symbol_symtab (sym);
-
-                 QUIT;
-
-                 /* Check first sole REAL_SYMTAB->FILENAME.  It does
-                    not need to be a substring of symtab_to_fullname as
-                    it may contain "./" etc.  */
-                 if ((file_matches (real_symtab->filename, files, nfiles, 0)
-                      || ((basenames_may_differ
-                           || file_matches (lbasename (real_symtab->filename),
-                                            files, nfiles, 1))
-                          && file_matches (symtab_to_fullname (real_symtab),
-                                           files, nfiles, 0)))
-                     && ((!preg.has_value ()
-                          || preg->exec (SYMBOL_NATURAL_NAME (sym), 0,
-                                         NULL, 0) == 0)
-                         && ((kind == VARIABLES_DOMAIN
-                              && SYMBOL_CLASS (sym) != LOC_TYPEDEF
-                              && SYMBOL_CLASS (sym) != LOC_UNRESOLVED
-                              && SYMBOL_CLASS (sym) != LOC_BLOCK
-                              /* LOC_CONST can be used for more than
-                                 just enums, e.g., c++ static const
-                                 members.  We only want to skip enums
-                                 here.  */
-                              && !(SYMBOL_CLASS (sym) == LOC_CONST
-                                   && (TYPE_CODE (SYMBOL_TYPE (sym))
-                                       == TYPE_CODE_ENUM))
-                              && (!treg.has_value ()
-                                  || treg_matches_sym_type_name (*treg, sym)))
-                             || (kind == FUNCTIONS_DOMAIN
-                                 && SYMBOL_CLASS (sym) == LOC_BLOCK
-                                 && (!treg.has_value ()
-                                     || treg_matches_sym_type_name (*treg,
-                                                                    sym)))
-                             || (kind == TYPES_DOMAIN
-                                 && SYMBOL_CLASS (sym) == LOC_TYPEDEF
-                                 && SYMBOL_DOMAIN (sym) != MODULE_DOMAIN)
-                             || (kind == MODULES_DOMAIN
-                                 && SYMBOL_DOMAIN (sym) == MODULE_DOMAIN
-                                 && SYMBOL_LINE (sym) != 0))))
-                   {
-                     /* match */
-                     result.emplace_back (i, sym);
-                   }
-               }
-           }
-       }
-    }
+      /* Expand symtabs within objfile that possibly contain matching
+        symbols.  */
+      found_msymbol |= expand_symtabs (objfile, preg);
 
-  if (!result.empty ())
-    sort_search_symbols_remove_dups (&result);
+      /* Find matching symbols within OBJFILE and add them in to the
+        RESULT_SET set.  Use a set here so that we can easily detect
+        duplicates as we go, and can therefore track how many unique
+        matches we have found so far.  */
+      if (!add_matching_symbols (objfile, preg, treg, &result_set))
+       break;
+    }
 
-  /* If there are no eyes, avoid all contact.  I mean, if there are
-     no debug symbols, then add matching minsyms.  But if the user wants
-     to see symbols matching a type regexp, then never give a minimal symbol,
-     as we assume that a minimal symbol does not have a type.  */
+  /* Convert the result set into a sorted result list, as std::set is
+     defined to be sorted then no explicit call to std::sort is needed.  */
+  std::vector<symbol_search> result (result_set.begin (), result_set.end ());
 
-  if ((found_misc || (nfiles == 0 && kind != FUNCTIONS_DOMAIN))
-      && !exclude_minsyms
+  /* If there are no debug symbols, then add matching minsyms.  But if the
+     user wants to see symbols matching a type regexp, then never give a
+     minimal symbol, as we assume that a minimal symbol does not have a
+     type.  */
+  if ((found_msymbol || (filenames.empty () && m_kind == VARIABLES_DOMAIN))
+      && !m_exclude_minsyms
       && !treg.has_value ())
     {
+      gdb_assert (m_kind == VARIABLES_DOMAIN || m_kind == FUNCTIONS_DOMAIN);
       for (objfile *objfile : current_program_space->objfiles ())
-       {
-         for (minimal_symbol *msymbol : objfile->msymbols ())
-           {
-             QUIT;
-
-             if (msymbol->created_by_gdb)
-               continue;
-
-             if (MSYMBOL_TYPE (msymbol) == ourtype
-                 || MSYMBOL_TYPE (msymbol) == ourtype2
-                 || MSYMBOL_TYPE (msymbol) == ourtype3
-                 || MSYMBOL_TYPE (msymbol) == ourtype4)
-               {
-                 if (!preg.has_value ()
-                     || preg->exec (MSYMBOL_NATURAL_NAME (msymbol), 0,
-                                    NULL, 0) == 0)
-                   {
-                     /* For functions we can do a quick check of whether the
-                        symbol might be found via find_pc_symtab.  */
-                     if (kind != FUNCTIONS_DOMAIN
-                         || (find_pc_compunit_symtab
-                             (MSYMBOL_VALUE_ADDRESS (objfile, msymbol))
-                             == NULL))
-                       {
-                         if (lookup_symbol_in_objfile_from_linkage_name
-                             (objfile, MSYMBOL_LINKAGE_NAME (msymbol),
-                              VAR_DOMAIN)
-                             .symbol == NULL)
-                           {
-                             /* match */
-                             result.emplace_back (i, msymbol, objfile);
-                           }
-                       }
-                   }
-               }
-           }
-       }
+       if (!add_matching_msymbols (objfile, preg, &result))
+         break;
     }
 
   return result;
 }
 
-/* Helper function for symtab_symbol_info, this function uses
-   the data returned from search_symbols() to print information
-   regarding the match to gdb_stdout.  If LAST is not NULL,
-   print file and line number information for the symbol as
-   well.  Skip printing the filename if it matches LAST.  */
+/* See symtab.h.  */
 
-static void
-print_symbol_info (enum search_domain kind,
-                  struct symbol *sym,
-                  int block, const char *last)
+std::string
+symbol_to_info_string (struct symbol *sym, int block,
+                      enum search_domain kind)
 {
-  scoped_switch_to_sym_language_if_auto l (sym);
-  struct symtab *s = symbol_symtab (sym);
+  std::string str;
 
-  if (last != NULL)
-    {
-      const char *s_filename = symtab_to_filename_for_display (s);
-
-      if (filename_cmp (last, s_filename) != 0)
-       {
-         printf_filtered (_("\nFile %ps:\n"),
-                          styled_string (file_name_style.style (),
-                                         s_filename));
-       }
-
-      if (SYMBOL_LINE (sym) != 0)
-       printf_filtered ("%d:\t", SYMBOL_LINE (sym));
-      else
-       puts_filtered ("\t");
-    }
+  gdb_assert (block == GLOBAL_BLOCK || block == STATIC_BLOCK);
 
   if (kind != TYPES_DOMAIN && block == STATIC_BLOCK)
-    printf_filtered ("static ");
+    str += "static ";
 
   /* Typedef that is not a C++ class.  */
   if (kind == TYPES_DOMAIN
       && SYMBOL_DOMAIN (sym) != STRUCT_DOMAIN)
     {
+      string_file tmp_stream;
+
       /* FIXME: For C (and C++) we end up with a difference in output here
         between how a typedef is printed, and non-typedefs are printed.
         The TYPEDEF_PRINT code places a ";" at the end in an attempt to
@@ -4771,31 +4842,70 @@ print_symbol_info (enum search_domain kind,
         For the struct printing case below, things are worse, we force
         printing of the ";" in this function, which is going to be wrong
         for languages that don't require a ";" between statements.  */
-      if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_TYPEDEF)
-       typedef_print (SYMBOL_TYPE (sym), sym, gdb_stdout);
+      if (SYMBOL_TYPE (sym)->code () == TYPE_CODE_TYPEDEF)
+       typedef_print (SYMBOL_TYPE (sym), sym, &tmp_stream);
       else
-       {
-         type_print (SYMBOL_TYPE (sym), "", gdb_stdout, -1);
-         printf_filtered ("\n");
-       }
+       type_print (SYMBOL_TYPE (sym), "", &tmp_stream, -1);
+      str += tmp_stream.string ();
     }
   /* variable, func, or typedef-that-is-c++-class.  */
   else if (kind < TYPES_DOMAIN
           || (kind == TYPES_DOMAIN
               && SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN))
     {
+      string_file tmp_stream;
+
       type_print (SYMBOL_TYPE (sym),
                  (SYMBOL_CLASS (sym) == LOC_TYPEDEF
-                  ? "" : SYMBOL_PRINT_NAME (sym)),
-                 gdb_stdout, 0);
+                  ? "" : sym->print_name ()),
+                 &tmp_stream, 0);
 
-      printf_filtered (";\n");
+      str += tmp_stream.string ();
+      str += ";";
     }
   /* Printing of modules is currently done here, maybe at some future
      point we might want a language specific method to print the module
      symbol so that we can customise the output more.  */
   else if (kind == MODULES_DOMAIN)
-    printf_filtered ("%s\n", SYMBOL_PRINT_NAME (sym));
+    str += sym->print_name ();
+
+  return str;
+}
+
+/* Helper function for symbol info commands, for example 'info functions',
+   'info variables', etc.  KIND is the kind of symbol we searched for, and
+   BLOCK is the type of block the symbols was found in, either GLOBAL_BLOCK
+   or STATIC_BLOCK.  SYM is the symbol we found.  If LAST is not NULL,
+   print file and line number information for the symbol as well.  Skip
+   printing the filename if it matches LAST.  */
+
+static void
+print_symbol_info (enum search_domain kind,
+                  struct symbol *sym,
+                  int block, const char *last)
+{
+  scoped_switch_to_sym_language_if_auto l (sym);
+  struct symtab *s = symbol_symtab (sym);
+
+  if (last != NULL)
+    {
+      const char *s_filename = symtab_to_filename_for_display (s);
+
+      if (filename_cmp (last, s_filename) != 0)
+       {
+         printf_filtered (_("\nFile %ps:\n"),
+                          styled_string (file_name_style.style (),
+                                         s_filename));
+       }
+
+      if (SYMBOL_LINE (sym) != 0)
+       printf_filtered ("%d:\t", SYMBOL_LINE (sym));
+      else
+       puts_filtered ("\t");
+    }
+
+  std::string str = symbol_to_info_string (sym, block, kind);
+  printf_filtered ("%s\n", str.c_str ());
 }
 
 /* This help function for symtab_symbol_info() prints information
@@ -4804,7 +4914,7 @@ print_symbol_info (enum search_domain kind,
 static void
 print_msymbol_info (struct bound_minimal_symbol msymbol)
 {
-  struct gdbarch *gdbarch = get_objfile_arch (msymbol.objfile);
+  struct gdbarch *gdbarch = msymbol.objfile->arch ();
   char *tmp;
 
   if (gdbarch_addr_bit (gdbarch) <= 32)
@@ -4821,8 +4931,7 @@ print_msymbol_info (struct bound_minimal_symbol msymbol)
 
   printf_filtered (_("%ps  %ps\n"),
                   styled_string (address_style.style (), tmp),
-                  styled_string (sym_style,
-                                 MSYMBOL_PRINT_NAME (msymbol.minsym)));
+                  styled_string (sym_style, msymbol.minsym->print_name ()));
 }
 
 /* This is the guts of the commands "info functions", "info types", and
@@ -4845,10 +4954,10 @@ symtab_symbol_info (bool quiet, bool exclude_minsyms,
   if (regexp != nullptr && *regexp == '\0')
     regexp = nullptr;
 
-  /* Must make sure that if we're interrupted, symbols gets freed.  */
-  std::vector<symbol_search> symbols = search_symbols (regexp, kind,
-                                                      t_regexp, 0, NULL,
-                                                      exclude_minsyms);
+  global_symbol_searcher spec (kind, regexp);
+  spec.set_symbol_type_regexp (t_regexp);
+  spec.set_exclude_minsyms (exclude_minsyms);
+  std::vector<symbol_search> symbols = spec.search ();
 
   if (!quiet)
     {
@@ -4905,13 +5014,13 @@ symtab_symbol_info (bool quiet, bool exclude_minsyms,
    and 'info functions' commands.  These correspond to the -q, -t, and -n
    options.  */
 
-struct info_print_options
+struct info_vars_funcs_options
 {
   bool quiet = false;
   bool exclude_minsyms = false;
   char *type_regexp = nullptr;
 
-  ~info_print_options ()
+  ~info_vars_funcs_options ()
   {
     xfree (type_regexp);
   }
@@ -4920,24 +5029,25 @@ struct info_print_options
 /* The options used by the 'info variables' and 'info functions'
    commands.  */
 
-static const gdb::option::option_def info_print_options_defs[] = {
-  gdb::option::boolean_option_def<info_print_options> {
+static const gdb::option::option_def info_vars_funcs_options_defs[] = {
+  gdb::option::boolean_option_def<info_vars_funcs_options> {
     "q",
-    [] (info_print_options *opt) { return &opt->quiet; },
+    [] (info_vars_funcs_options *opt) { return &opt->quiet; },
     nullptr, /* show_cmd_cb */
     nullptr /* set_doc */
   },
 
-  gdb::option::boolean_option_def<info_print_options> {
+  gdb::option::boolean_option_def<info_vars_funcs_options> {
     "n",
-    [] (info_print_options *opt) { return &opt->exclude_minsyms; },
+    [] (info_vars_funcs_options *opt) { return &opt->exclude_minsyms; },
     nullptr, /* show_cmd_cb */
     nullptr /* set_doc */
   },
 
-  gdb::option::string_option_def<info_print_options> {
+  gdb::option::string_option_def<info_vars_funcs_options> {
     "t",
-    [] (info_print_options *opt) { return &opt->type_regexp; },
+    [] (info_vars_funcs_options *opt) { return &opt->type_regexp;
+  },
     nullptr, /* show_cmd_cb */
     nullptr /* set_doc */
   }
@@ -4947,20 +5057,20 @@ static const gdb::option::option_def info_print_options_defs[] = {
    functions'.  */
 
 static gdb::option::option_def_group
-make_info_print_options_def_group (info_print_options *opts)
+make_info_vars_funcs_options_def_group (info_vars_funcs_options *opts)
 {
-  return {{info_print_options_defs}, opts};
+  return {{info_vars_funcs_options_defs}, opts};
 }
 
 /* Command completer for 'info variables' and 'info functions'.  */
 
 static void
-info_print_command_completer (struct cmd_list_element *ignore,
-                             completion_tracker &tracker,
-                             const char *text, const char * /* word */)
+info_vars_funcs_command_completer (struct cmd_list_element *ignore,
+                                  completion_tracker &tracker,
+                                  const char *text, const char * /* word */)
 {
   const auto group
-    = make_info_print_options_def_group (nullptr);
+    = make_info_vars_funcs_options_def_group (nullptr);
   if (gdb::option::complete_options
       (tracker, &text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, group))
     return;
@@ -4974,8 +5084,8 @@ info_print_command_completer (struct cmd_list_element *ignore,
 static void
 info_variables_command (const char *args, int from_tty)
 {
-  info_print_options opts;
-  auto grp = make_info_print_options_def_group (&opts);
+  info_vars_funcs_options opts;
+  auto grp = make_info_vars_funcs_options_def_group (&opts);
   gdb::option::process_options
     (&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, grp);
   if (args != nullptr && *args == '\0')
@@ -4990,8 +5100,9 @@ info_variables_command (const char *args, int from_tty)
 static void
 info_functions_command (const char *args, int from_tty)
 {
-  info_print_options opts;
-  auto grp = make_info_print_options_def_group (&opts);
+  info_vars_funcs_options opts;
+
+  auto grp = make_info_vars_funcs_options_def_group (&opts);
   gdb::option::process_options
     (&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, grp);
   if (args != nullptr && *args == '\0')
@@ -5075,23 +5186,13 @@ info_modules_command (const char *args, int from_tty)
                      from_tty);
 }
 
-/* Breakpoint all functions matching regular expression.  */
-
-void
-rbreak_command_wrapper (char *regexp, int from_tty)
-{
-  rbreak_command (regexp, from_tty);
-}
-
 static void
 rbreak_command (const char *regexp, int from_tty)
 {
   std::string string;
-  const char **files = NULL;
-  const char *file_name;
-  int nfiles = 0;
+  const char *file_name = nullptr;
 
-  if (regexp)
+  if (regexp != nullptr)
     {
       const char *colon = strchr (regexp, ':');
 
@@ -5107,17 +5208,14 @@ rbreak_command (const char *regexp, int from_tty)
          while (isspace (local_name[colon_index]))
            local_name[colon_index--] = 0;
          file_name = local_name;
-         files = &file_name;
-         nfiles = 1;
          regexp = skip_spaces (colon + 1);
        }
     }
 
-  std::vector<symbol_search> symbols = search_symbols (regexp,
-                                                      FUNCTIONS_DOMAIN,
-                                                      NULL,
-                                                      nfiles, files,
-                                                      false);
+  global_symbol_searcher spec (FUNCTIONS_DOMAIN, regexp);
+  if (file_name != nullptr)
+    spec.filenames.push_back (file_name);
+  std::vector<symbol_search> symbols = spec.search ();
 
   scoped_rbreak_breakpoints finalize;
   for (const symbol_search &p : symbols)
@@ -5128,18 +5226,18 @@ rbreak_command (const char *regexp, int from_tty)
          const char *fullname = symtab_to_fullname (symtab);
 
          string = string_printf ("%s:'%s'", fullname,
-                                 SYMBOL_LINKAGE_NAME (p.symbol));
+                                 p.symbol->linkage_name ());
          break_command (&string[0], from_tty);
          print_symbol_info (FUNCTIONS_DOMAIN, p.symbol, p.block, NULL);
        }
       else
        {
          string = string_printf ("'%s'",
-                                 MSYMBOL_LINKAGE_NAME (p.msymbol.minsym));
+                                 p.msymbol.minsym->linkage_name ());
 
          break_command (&string[0], from_tty);
          printf_filtered ("<function, no debug info> %s;\n",
-                          MSYMBOL_PRINT_NAME (p.msymbol.minsym));
+                          p.msymbol.minsym->print_name ());
        }
     }
 }
@@ -5162,7 +5260,7 @@ compare_symbol_name (const char *symbol_name, language symbol_language,
 
 /*  See symtab.h.  */
 
-void
+bool
 completion_list_add_name (completion_tracker &tracker,
                          language symbol_language,
                          const char *symname,
@@ -5174,7 +5272,7 @@ completion_list_add_name (completion_tracker &tracker,
 
   /* Clip symbols that cannot match.  */
   if (!compare_symbol_name (symname, symbol_language, lookup_name, match_res))
-    return;
+    return false;
 
   /* Refresh SYMNAME from the match string.  It's potentially
      different depending on language.  (E.g., on Ada, the match may be
@@ -5198,6 +5296,8 @@ completion_list_add_name (completion_tracker &tracker,
     tracker.add_completion (std::move (completion),
                            &match_res.match_for_lcd, text, word);
   }
+
+  return true;
 }
 
 /* completion_list_add_name wrapper for struct symbol.  */
@@ -5208,9 +5308,31 @@ completion_list_add_symbol (completion_tracker &tracker,
                            const lookup_name_info &lookup_name,
                            const char *text, const char *word)
 {
-  completion_list_add_name (tracker, SYMBOL_LANGUAGE (sym),
-                           SYMBOL_NATURAL_NAME (sym),
-                           lookup_name, text, word);
+  if (!completion_list_add_name (tracker, sym->language (),
+                                sym->natural_name (),
+                                lookup_name, text, word))
+    return;
+
+  /* C++ function symbols include the parameters within both the msymbol
+     name and the symbol name.  The problem is that the msymbol name will
+     describe the parameters in the most basic way, with typedefs stripped
+     out, while the symbol name will represent the types as they appear in
+     the program.  This means we will see duplicate entries in the
+     completion tracker.  The following converts the symbol name back to
+     the msymbol name and removes the msymbol name from the completion
+     tracker.  */
+  if (sym->language () == language_cplus
+      && SYMBOL_DOMAIN (sym) == VAR_DOMAIN
+      && SYMBOL_CLASS (sym) == LOC_BLOCK)
+    {
+      /* The call to canonicalize returns the empty string if the input
+        string is already in canonical form, thanks to this we don't
+        remove the symbol we just added above.  */
+      gdb::unique_xmalloc_ptr<char> str
+       = cp_canonicalize_string_no_typedefs (sym->natural_name ());
+      if (str != nullptr)
+       tracker.remove_completion (str.get ());
+    }
 }
 
 /* completion_list_add_name wrapper for struct minimal_symbol.  */
@@ -5221,8 +5343,8 @@ completion_list_add_msymbol (completion_tracker &tracker,
                             const lookup_name_info &lookup_name,
                             const char *text, const char *word)
 {
-  completion_list_add_name (tracker, MSYMBOL_LANGUAGE (sym),
-                           MSYMBOL_NATURAL_NAME (sym),
+  completion_list_add_name (tracker, sym->language (),
+                           sym->natural_name (),
                            lookup_name, text, word);
 }
 
@@ -5242,7 +5364,7 @@ completion_list_objc_symbol (completion_tracker &tracker,
   const char *method, *category, *selector;
   char *tmp2 = NULL;
 
-  method = MSYMBOL_NATURAL_NAME (msymbol);
+  method = msymbol->natural_name ();
 
   /* Is it a method?  */
   if ((method[0] != '-') && (method[0] != '+'))
@@ -5349,13 +5471,13 @@ completion_list_add_fields (completion_tracker &tracker,
   if (SYMBOL_CLASS (sym) == LOC_TYPEDEF)
     {
       struct type *t = SYMBOL_TYPE (sym);
-      enum type_code c = TYPE_CODE (t);
+      enum type_code c = t->code ();
       int j;
 
       if (c == TYPE_CODE_UNION || c == TYPE_CODE_STRUCT)
-       for (j = TYPE_N_BASECLASSES (t); j < TYPE_NFIELDS (t); j++)
+       for (j = TYPE_N_BASECLASSES (t); j < t->num_fields (); j++)
          if (TYPE_FIELD_NAME (t, j))
-           completion_list_add_name (tracker, SYMBOL_LANGUAGE (sym),
+           completion_list_add_name (tracker, sym->language (),
                                      TYPE_FIELD_NAME (t, j),
                                      lookup_name, text, word);
     }
@@ -5366,7 +5488,7 @@ completion_list_add_fields (completion_tracker &tracker,
 bool
 symbol_is_function_or_method (symbol *sym)
 {
-  switch (TYPE_CODE (SYMBOL_TYPE (sym)))
+  switch (SYMBOL_TYPE (sym)->code ())
     {
     case TYPE_CODE_FUNC:
     case TYPE_CODE_METHOD:
@@ -5401,7 +5523,7 @@ find_gnu_ifunc (const symbol *sym)
   if (SYMBOL_CLASS (sym) != LOC_BLOCK)
     return {};
 
-  lookup_name_info lookup_name (SYMBOL_SEARCH_NAME (sym),
+  lookup_name_info lookup_name (sym->search_name (),
                                symbol_name_match_type::SEARCH_NAME);
   struct objfile *objfile = symbol_objfile (sym);
 
@@ -5417,7 +5539,7 @@ find_gnu_ifunc (const symbol *sym)
          CORE_ADDR msym_addr = MSYMBOL_VALUE_ADDRESS (objfile, minsym);
          if (MSYMBOL_TYPE (minsym) == mst_data_gnu_ifunc)
            {
-             struct gdbarch *gdbarch = get_objfile_arch (objfile);
+             struct gdbarch *gdbarch = objfile->arch ();
              msym_addr
                = gdbarch_convert_from_func_ptr_addr (gdbarch,
                                                      msym_addr,
@@ -5466,7 +5588,7 @@ add_symtab_completions (struct compunit_symtab *cust,
 
          if (code == TYPE_CODE_UNDEF
              || (SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN
-                 && TYPE_CODE (SYMBOL_TYPE (sym)) == code))
+                 && SYMBOL_TYPE (sym)->code () == code))
            completion_list_add_symbol (tracker, sym,
                                        lookup_name,
                                        text, word);
@@ -5617,7 +5739,7 @@ default_collect_symbol_completion_matches_break_on
                                            sym_text, word);
              }
            else if (SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN
-                    && TYPE_CODE (SYMBOL_TYPE (sym)) == code)
+                    && SYMBOL_TYPE (sym)->code () == code)
              completion_list_add_symbol (tracker, sym, lookup_name,
                                          sym_text, word);
          }
@@ -6038,6 +6160,16 @@ find_main_name (void)
 
   /* The languages above didn't identify the name of the main procedure.
      Fallback to "main".  */
+
+  /* Try to find language for main in psymtabs.  */
+  enum language lang
+    = find_quick_global_symbol_language ("main", VAR_DOMAIN);
+  if (lang != language_unknown)
+    {
+      set_main_name ("main", lang);
+      return;
+    }
+
   set_main_name ("main", language_unknown);
 }
 
@@ -6210,53 +6342,6 @@ initialize_ordinary_address_classes (void)
 
 \f
 
-/* Helper function to initialize the fields of an objfile-owned symbol.
-   It assumed that *SYM is already all zeroes.  */
-
-static void
-initialize_objfile_symbol_1 (struct symbol *sym)
-{
-  SYMBOL_OBJFILE_OWNED (sym) = 1;
-  SYMBOL_SECTION (sym) = -1;
-}
-
-/* Initialize the symbol SYM, and mark it as being owned by an objfile.  */
-
-void
-initialize_objfile_symbol (struct symbol *sym)
-{
-  memset (sym, 0, sizeof (*sym));
-  initialize_objfile_symbol_1 (sym);
-}
-
-/* Allocate and initialize a new 'struct symbol' on OBJFILE's
-   obstack.  */
-
-struct symbol *
-allocate_symbol (struct objfile *objfile)
-{
-  struct symbol *result;
-
-  result = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct symbol);
-  initialize_objfile_symbol_1 (result);
-
-  return result;
-}
-
-/* Allocate and initialize a new 'struct template_symbol' on OBJFILE's
-   obstack.  */
-
-struct template_symbol *
-allocate_template_symbol (struct objfile *objfile)
-{
-  struct template_symbol *result;
-
-  result = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct template_symbol);
-  initialize_objfile_symbol_1 (result);
-
-  return result;
-}
-
 /* See symtab.h.  */
 
 struct objfile *
@@ -6273,7 +6358,7 @@ symbol_arch (const struct symbol *symbol)
 {
   if (!SYMBOL_OBJFILE_OWNED (symbol))
     return symbol->owner.arch;
-  return get_objfile_arch (SYMTAB_OBJFILE (symbol->owner.symtab));
+  return SYMTAB_OBJFILE (symbol->owner.symtab)->arch ();
 }
 
 /* See symtab.h.  */
@@ -6302,16 +6387,19 @@ get_symbol_address (const struct symbol *sym)
   gdb_assert (sym->maybe_copied);
   gdb_assert (SYMBOL_CLASS (sym) == LOC_STATIC);
 
-  const char *linkage_name = SYMBOL_LINKAGE_NAME (sym);
+  const char *linkage_name = sym->linkage_name ();
 
   for (objfile *objfile : current_program_space->objfiles ())
     {
+      if (objfile->separate_debug_objfile_backlink != nullptr)
+       continue;
+
       bound_minimal_symbol minsym
        = lookup_minimal_symbol_linkage (linkage_name, objfile);
       if (minsym.minsym != nullptr)
        return BMSYMBOL_VALUE_ADDRESS (minsym);
     }
-  return sym->ginfo.value.address;
+  return sym->value.address;
 }
 
 /* See symtab.h.  */
@@ -6322,11 +6410,12 @@ get_msymbol_address (struct objfile *objf, const struct minimal_symbol *minsym)
   gdb_assert (minsym->maybe_copied);
   gdb_assert ((objf->flags & OBJF_MAINLINE) == 0);
 
-  const char *linkage_name = MSYMBOL_LINKAGE_NAME (minsym);
+  const char *linkage_name = minsym->linkage_name ();
 
   for (objfile *objfile : current_program_space->objfiles ())
     {
-      if ((objfile->flags & OBJF_MAINLINE) != 0)
+      if (objfile->separate_debug_objfile_backlink == nullptr
+         && (objfile->flags & OBJF_MAINLINE) != 0)
        {
          bound_minimal_symbol found
            = lookup_minimal_symbol_linkage (linkage_name, objfile);
@@ -6334,14 +6423,313 @@ get_msymbol_address (struct objfile *objf, const struct minimal_symbol *minsym)
            return BMSYMBOL_VALUE_ADDRESS (found);
        }
     }
-  return (minsym->value.address
-         + ANOFFSET (objf->section_offsets, minsym->section));
+  return minsym->value.address + objf->section_offsets[minsym->section];
 }
 
 \f
 
+/* Hold the sub-commands of 'info module'.  */
+
+static struct cmd_list_element *info_module_cmdlist = NULL;
+
+/* See symtab.h.  */
+
+std::vector<module_symbol_search>
+search_module_symbols (const char *module_regexp, const char *regexp,
+                      const char *type_regexp, search_domain kind)
+{
+  std::vector<module_symbol_search> results;
+
+  /* Search for all modules matching MODULE_REGEXP.  */
+  global_symbol_searcher spec1 (MODULES_DOMAIN, module_regexp);
+  spec1.set_exclude_minsyms (true);
+  std::vector<symbol_search> modules = spec1.search ();
+
+  /* Now search for all symbols of the required KIND matching the required
+     regular expressions.  We figure out which ones are in which modules
+     below.  */
+  global_symbol_searcher spec2 (kind, regexp);
+  spec2.set_symbol_type_regexp (type_regexp);
+  spec2.set_exclude_minsyms (true);
+  std::vector<symbol_search> symbols = spec2.search ();
+
+  /* Now iterate over all MODULES, checking to see which items from
+     SYMBOLS are in each module.  */
+  for (const symbol_search &p : modules)
+    {
+      QUIT;
+
+      /* This is a module.  */
+      gdb_assert (p.symbol != nullptr);
+
+      std::string prefix = p.symbol->print_name ();
+      prefix += "::";
+
+      for (const symbol_search &q : symbols)
+       {
+         if (q.symbol == nullptr)
+           continue;
+
+         if (strncmp (q.symbol->print_name (), prefix.c_str (),
+                      prefix.size ()) != 0)
+           continue;
+
+         results.push_back ({p, q});
+       }
+    }
+
+  return results;
+}
+
+/* Implement the core of both 'info module functions' and 'info module
+   variables'.  */
+
+static void
+info_module_subcommand (bool quiet, const char *module_regexp,
+                       const char *regexp, const char *type_regexp,
+                       search_domain kind)
+{
+  /* Print a header line.  Don't build the header line bit by bit as this
+     prevents internationalisation.  */
+  if (!quiet)
+    {
+      if (module_regexp == nullptr)
+       {
+         if (type_regexp == nullptr)
+           {
+             if (regexp == nullptr)
+               printf_filtered ((kind == VARIABLES_DOMAIN
+                                 ? _("All variables in all modules:")
+                                 : _("All functions in all modules:")));
+             else
+               printf_filtered
+                 ((kind == VARIABLES_DOMAIN
+                   ? _("All variables matching regular expression"
+                       " \"%s\" in all modules:")
+                   : _("All functions matching regular expression"
+                       " \"%s\" in all modules:")),
+                  regexp);
+           }
+         else
+           {
+             if (regexp == nullptr)
+               printf_filtered
+                 ((kind == VARIABLES_DOMAIN
+                   ? _("All variables with type matching regular "
+                       "expression \"%s\" in all modules:")
+                   : _("All functions with type matching regular "
+                       "expression \"%s\" in all modules:")),
+                  type_regexp);
+             else
+               printf_filtered
+                 ((kind == VARIABLES_DOMAIN
+                   ? _("All variables matching regular expression "
+                       "\"%s\",\n\twith type matching regular "
+                       "expression \"%s\" in all modules:")
+                   : _("All functions matching regular expression "
+                       "\"%s\",\n\twith type matching regular "
+                       "expression \"%s\" in all modules:")),
+                  regexp, type_regexp);
+           }
+       }
+      else
+       {
+         if (type_regexp == nullptr)
+           {
+             if (regexp == nullptr)
+               printf_filtered
+                 ((kind == VARIABLES_DOMAIN
+                   ? _("All variables in all modules matching regular "
+                       "expression \"%s\":")
+                   : _("All functions in all modules matching regular "
+                       "expression \"%s\":")),
+                  module_regexp);
+             else
+               printf_filtered
+                 ((kind == VARIABLES_DOMAIN
+                   ? _("All variables matching regular expression "
+                       "\"%s\",\n\tin all modules matching regular "
+                       "expression \"%s\":")
+                   : _("All functions matching regular expression "
+                       "\"%s\",\n\tin all modules matching regular "
+                       "expression \"%s\":")),
+                  regexp, module_regexp);
+           }
+         else
+           {
+             if (regexp == nullptr)
+               printf_filtered
+                 ((kind == VARIABLES_DOMAIN
+                   ? _("All variables with type matching regular "
+                       "expression \"%s\"\n\tin all modules matching "
+                       "regular expression \"%s\":")
+                   : _("All functions with type matching regular "
+                       "expression \"%s\"\n\tin all modules matching "
+                       "regular expression \"%s\":")),
+                  type_regexp, module_regexp);
+             else
+               printf_filtered
+                 ((kind == VARIABLES_DOMAIN
+                   ? _("All variables matching regular expression "
+                       "\"%s\",\n\twith type matching regular expression "
+                       "\"%s\",\n\tin all modules matching regular "
+                       "expression \"%s\":")
+                   : _("All functions matching regular expression "
+                       "\"%s\",\n\twith type matching regular expression "
+                       "\"%s\",\n\tin all modules matching regular "
+                       "expression \"%s\":")),
+                  regexp, type_regexp, module_regexp);
+           }
+       }
+      printf_filtered ("\n");
+    }
+
+  /* Find all symbols of type KIND matching the given regular expressions
+     along with the symbols for the modules in which those symbols
+     reside.  */
+  std::vector<module_symbol_search> module_symbols
+    = search_module_symbols (module_regexp, regexp, type_regexp, kind);
+
+  std::sort (module_symbols.begin (), module_symbols.end (),
+            [] (const module_symbol_search &a, const module_symbol_search &b)
+            {
+              if (a.first < b.first)
+                return true;
+              else if (a.first == b.first)
+                return a.second < b.second;
+              else
+                return false;
+            });
+
+  const char *last_filename = "";
+  const symbol *last_module_symbol = nullptr;
+  for (const module_symbol_search &ms : module_symbols)
+    {
+      const symbol_search &p = ms.first;
+      const symbol_search &q = ms.second;
+
+      gdb_assert (q.symbol != nullptr);
+
+      if (last_module_symbol != p.symbol)
+       {
+         printf_filtered ("\n");
+         printf_filtered (_("Module \"%s\":\n"), p.symbol->print_name ());
+         last_module_symbol = p.symbol;
+         last_filename = "";
+       }
+
+      print_symbol_info (FUNCTIONS_DOMAIN, q.symbol, q.block,
+                        last_filename);
+      last_filename
+       = symtab_to_filename_for_display (symbol_symtab (q.symbol));
+    }
+}
+
+/* Hold the option values for the 'info module .....' sub-commands.  */
+
+struct info_modules_var_func_options
+{
+  bool quiet = false;
+  char *type_regexp = nullptr;
+  char *module_regexp = nullptr;
+
+  ~info_modules_var_func_options ()
+  {
+    xfree (type_regexp);
+    xfree (module_regexp);
+  }
+};
+
+/* The options used by 'info module variables' and 'info module functions'
+   commands.  */
+
+static const gdb::option::option_def info_modules_var_func_options_defs [] = {
+  gdb::option::boolean_option_def<info_modules_var_func_options> {
+    "q",
+    [] (info_modules_var_func_options *opt) { return &opt->quiet; },
+    nullptr, /* show_cmd_cb */
+    nullptr /* set_doc */
+  },
+
+  gdb::option::string_option_def<info_modules_var_func_options> {
+    "t",
+    [] (info_modules_var_func_options *opt) { return &opt->type_regexp; },
+    nullptr, /* show_cmd_cb */
+    nullptr /* set_doc */
+  },
+
+  gdb::option::string_option_def<info_modules_var_func_options> {
+    "m",
+    [] (info_modules_var_func_options *opt) { return &opt->module_regexp; },
+    nullptr, /* show_cmd_cb */
+    nullptr /* set_doc */
+  }
+};
+
+/* Return the option group used by the 'info module ...' sub-commands.  */
+
+static inline gdb::option::option_def_group
+make_info_modules_var_func_options_def_group
+       (info_modules_var_func_options *opts)
+{
+  return {{info_modules_var_func_options_defs}, opts};
+}
+
+/* Implements the 'info module functions' command.  */
+
+static void
+info_module_functions_command (const char *args, int from_tty)
+{
+  info_modules_var_func_options opts;
+  auto grp = make_info_modules_var_func_options_def_group (&opts);
+  gdb::option::process_options
+    (&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, grp);
+  if (args != nullptr && *args == '\0')
+    args = nullptr;
+
+  info_module_subcommand (opts.quiet, opts.module_regexp, args,
+                         opts.type_regexp, FUNCTIONS_DOMAIN);
+}
+
+/* Implements the 'info module variables' command.  */
+
+static void
+info_module_variables_command (const char *args, int from_tty)
+{
+  info_modules_var_func_options opts;
+  auto grp = make_info_modules_var_func_options_def_group (&opts);
+  gdb::option::process_options
+    (&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, grp);
+  if (args != nullptr && *args == '\0')
+    args = nullptr;
+
+  info_module_subcommand (opts.quiet, opts.module_regexp, args,
+                         opts.type_regexp, VARIABLES_DOMAIN);
+}
+
+/* Command completer for 'info module ...' sub-commands.  */
+
+static void
+info_module_var_func_command_completer (struct cmd_list_element *ignore,
+                                       completion_tracker &tracker,
+                                       const char *text,
+                                       const char * /* word */)
+{
+
+  const auto group = make_info_modules_var_func_options_def_group (nullptr);
+  if (gdb::option::complete_options
+      (tracker, &text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, group))
+    return;
+
+  const char *word = advance_to_expression_complete_word_point (tracker, text);
+  symbol_completer (ignore, tracker, text, word);
+}
+
+\f
+
+void _initialize_symtab ();
 void
-_initialize_symtab (void)
+_initialize_symtab ()
 {
   cmd_list_element *c;
 
@@ -6354,7 +6742,7 @@ Usage: info variables [-q] [-n] [-t TYPEREGEXP] [NAMEREGEXP]\n\
 Prints the global and static variables.\n"),
                                      _("global and static variables"),
                                      true));
-  set_cmd_completer_handle_brkchars (c, info_print_command_completer);
+  set_cmd_completer_handle_brkchars (c, info_vars_funcs_command_completer);
   if (dbx_commands)
     {
       c = add_com ("whereis", class_info, info_variables_command,
@@ -6364,7 +6752,7 @@ Usage: whereis [-q] [-n] [-t TYPEREGEXP] [NAMEREGEXP]\n\
 Prints the global and static variables.\n"),
                                         _("global and static variables"),
                                         true));
-      set_cmd_completer_handle_brkchars (c, info_print_command_completer);
+      set_cmd_completer_handle_brkchars (c, info_vars_funcs_command_completer);
     }
 
   c = add_info ("functions", info_functions_command,
@@ -6374,7 +6762,7 @@ Usage: info functions [-q] [-n] [-t TYPEREGEXP] [NAMEREGEXP]\n\
 Prints the functions.\n"),
                                      _("functions"),
                                      true));
-  set_cmd_completer_handle_brkchars (c, info_print_command_completer);
+  set_cmd_completer_handle_brkchars (c, info_vars_funcs_command_completer);
 
   c = add_info ("types", info_types_command, _("\
 All type names, or those matching REGEXP.\n\
@@ -6402,6 +6790,45 @@ Options:\n\
                _("All module names, or those matching REGEXP."));
   set_cmd_completer_handle_brkchars (c, info_types_command_completer);
 
+  add_basic_prefix_cmd ("module", class_info, _("\
+Print information about modules."),
+                       &info_module_cmdlist, "info module ",
+                       0, &infolist);
+
+  c = add_cmd ("functions", class_info, info_module_functions_command, _("\
+Display functions arranged by modules.\n\
+Usage: info module functions [-q] [-m MODREGEXP] [-t TYPEREGEXP] [REGEXP]\n\
+Print a summary of all functions within each Fortran module, grouped by\n\
+module and file.  For each function the line on which the function is\n\
+defined is given along with the type signature and name of the function.\n\
+\n\
+If REGEXP is provided then only functions whose name matches REGEXP are\n\
+listed.  If MODREGEXP is provided then only functions in modules matching\n\
+MODREGEXP are listed.  If TYPEREGEXP is given then only functions whose\n\
+type signature matches TYPEREGEXP are listed.\n\
+\n\
+The -q flag suppresses printing some header information."),
+              &info_module_cmdlist);
+  set_cmd_completer_handle_brkchars
+    (c, info_module_var_func_command_completer);
+
+  c = add_cmd ("variables", class_info, info_module_variables_command, _("\
+Display variables arranged by modules.\n\
+Usage: info module variables [-q] [-m MODREGEXP] [-t TYPEREGEXP] [REGEXP]\n\
+Print a summary of all variables within each Fortran module, grouped by\n\
+module and file.  For each variable the line on which the variable is\n\
+defined is given along with the type and name of the variable.\n\
+\n\
+If REGEXP is provided then only variables whose name matches REGEXP are\n\
+listed.  If MODREGEXP is provided then only variables in modules matching\n\
+MODREGEXP are listed.  If TYPEREGEXP is given then only variables whose\n\
+type matches TYPEREGEXP are listed.\n\
+\n\
+The -q flag suppresses printing some header information."),
+              &info_module_cmdlist);
+  set_cmd_completer_handle_brkchars
+    (c, info_module_var_func_command_completer);
+
   add_com ("rbreak", class_breakpoint, rbreak_command,
           _("Set a breakpoint for all functions matching REGEXP."));
 
This page took 0.056953 seconds and 4 git commands to generate.