Test case for BZ 25065
[deliverable/binutils-gdb.git] / gdb / symtab.c
index a6a9dc9c6eba8a8774e9189bf6e0de5a60ea4b9c..8f46321f43d79019446180e62296d3f6a7c0a4d0 100644 (file)
@@ -299,6 +299,7 @@ search_domain_name (enum search_domain e)
     case VARIABLES_DOMAIN: return "VARIABLES_DOMAIN";
     case FUNCTIONS_DOMAIN: return "FUNCTIONS_DOMAIN";
     case TYPES_DOMAIN: return "TYPES_DOMAIN";
+    case MODULES_DOMAIN: return "MODULES_DOMAIN";
     case ALL_DOMAIN: return "ALL_DOMAIN";
     default: gdb_assert_not_reached ("bad search_domain");
     }
@@ -769,20 +770,26 @@ 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)
 {
@@ -828,7 +835,7 @@ symbol_find_demangled_name (struct general_symbol_info *gsymbol,
 
 void
 symbol_set_names (struct general_symbol_info *gsymbol,
-                 const char *linkage_name, int len, bool copy_name,
+                 gdb::string_view linkage_name, bool copy_name,
                  struct objfile_per_bfd_storage *per_bfd)
 {
   struct demangled_name_entry **slot;
@@ -838,14 +845,14 @@ symbol_set_names (struct general_symbol_info *gsymbol,
       /* 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;
+       gsymbol->name = linkage_name.data ();
       else
        {
          char *name = (char *) obstack_alloc (&per_bfd->storage_obstack,
-                                              len + 1);
+                                              linkage_name.length () + 1);
 
-         memcpy (name, linkage_name, len);
-         name[len] = '\0';
+         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);
@@ -856,7 +863,7 @@ symbol_set_names (struct general_symbol_info *gsymbol,
   if (per_bfd->demangled_names_hash == NULL)
     create_demangled_names_hash (per_bfd);
 
-  struct demangled_name_entry entry (gdb::string_view (linkage_name, len));
+  struct demangled_name_entry entry (linkage_name);
   slot = ((struct demangled_name_entry **)
          htab_find_slot (per_bfd->demangled_names_hash.get (),
                          &entry, INSERT));
@@ -870,20 +877,28 @@ symbol_set_names (struct general_symbol_info *gsymbol,
       /* 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
          this copy because demangling needs a nullterminated string.  */
-      const char *linkage_name_copy;
+      gdb::string_view linkage_name_copy;
       if (copy_name)
        {
-         char *alloc_name = (char *) alloca (len + 1);
-         memcpy (alloc_name, linkage_name, len);
-         alloc_name[len] = '\0';
+         char *alloc_name = (char *) alloca (linkage_name.length () + 1);
+         memcpy (alloc_name, linkage_name.data (), linkage_name.length ());
+         alloc_name[linkage_name.length ()] = '\0';
 
-         linkage_name_copy = alloc_name;
+         linkage_name_copy = gdb::string_view (alloc_name,
+                                               linkage_name.length ());
        }
       else
        linkage_name_copy = linkage_name;
 
-      gdb::unique_xmalloc_ptr<char> demangled_name_ptr
-       (symbol_find_demangled_name (gsymbol, linkage_name_copy));
+      /* 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.  */
+      gdb::unique_xmalloc_ptr<char> demangled_name
+       (gsymbol->language_specific.demangled_name
+        ? const_cast<char *> (gsymbol->language_specific.demangled_name)
+        : symbol_find_demangled_name (gsymbol, 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
@@ -900,8 +915,7 @@ symbol_set_names (struct general_symbol_info *gsymbol,
            = ((struct demangled_name_entry *)
               obstack_alloc (&per_bfd->storage_obstack,
                              sizeof (demangled_name_entry)));
-         new (*slot) demangled_name_entry
-           (gdb::string_view (linkage_name, len));
+         new (*slot) demangled_name_entry (linkage_name);
        }
       else
        {
@@ -910,14 +924,15 @@ symbol_set_names (struct general_symbol_info *gsymbol,
          *slot
            = ((struct demangled_name_entry *)
               obstack_alloc (&per_bfd->storage_obstack,
-                             sizeof (demangled_name_entry) + len + 1));
+                             sizeof (demangled_name_entry)
+                             + linkage_name.length () + 1));
          char *mangled_ptr = reinterpret_cast<char *> (*slot + 1);
-         memcpy (mangled_ptr, linkage_name, len);
-         mangled_ptr [len] = '\0';
+         memcpy (mangled_ptr, linkage_name.data (), linkage_name.length ());
+         mangled_ptr [linkage_name.length ()] = '\0';
          new (*slot) demangled_name_entry
-           (gdb::string_view (mangled_ptr, len));
+           (gdb::string_view (mangled_ptr, linkage_name.length ()));
        }
-      (*slot)->demangled = std::move (demangled_name_ptr);
+      (*slot)->demangled = std::move (demangled_name);
       (*slot)->language = gsymbol->language;
     }
   else if (gsymbol->language == language_unknown
@@ -932,49 +947,47 @@ symbol_set_names (struct general_symbol_info *gsymbol,
     symbol_set_demangled_name (gsymbol, NULL, &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);
+      if (symbol_get_demangled_name (this) != NULL)
+       return symbol_get_demangled_name (this);
       break;
     case language_ada:
-      return ada_decode_symbol (gsymbol);
+      return ada_decode_symbol (this);
     default:
       break;
     }
-  return gsymbol->name;
+  return 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);
+      dem_name = symbol_get_demangled_name (this);
       break;
     case language_ada:
-      dem_name = ada_decode_symbol (gsymbol);
+      dem_name = ada_decode_symbol (this);
       break;
     default:
       break;
@@ -982,18 +995,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 name;
   else
-    return symbol_natural_name (gsymbol);
+    return natural_name ();
 }
 
 /* See symtab.h.  */
@@ -1004,7 +1014,7 @@ symbol_matches_search_name (const struct general_symbol_info *gsymbol,
 {
   symbol_name_matcher_ftype *name_match
     = get_symbol_name_matcher (language_def (gsymbol->language), name);
-  return name_match (symbol_search_name (gsymbol), name, NULL);
+  return name_match (gsymbol->search_name (), name, NULL);
 }
 
 \f
@@ -1144,7 +1154,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);
     }
 
@@ -1161,7 +1171,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.
 
@@ -1510,7 +1520,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;
              }
@@ -1757,7 +1767,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;
 }
@@ -1943,7 +1953,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));
            }
@@ -3115,7 +3125,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)
@@ -3129,7 +3139,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)
@@ -3137,7 +3147,7 @@ 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
@@ -3708,7 +3718,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
     {
@@ -3721,7 +3731,7 @@ 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);
@@ -4337,27 +4347,24 @@ 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
@@ -4377,8 +4384,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.
@@ -4395,7 +4401,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);
@@ -4434,30 +4440,10 @@ sort_search_symbols_remove_dups (std::vector<symbol_search> *result)
                 result->end ());
 }
 
-/* Search the symbol table for matches to the regular expression REGEXP,
-   returning the results.
-
-   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
-
-   Within each file the results are sorted locally; each symtab's global and
-   static blocks are separately alphabetized.
-   Duplicate entries are removed.
-
-   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;
@@ -4481,21 +4467,23 @@ search_symbols (const char *regexp, enum search_domain kind,
   gdb::optional<compiled_regex> preg;
   gdb::optional<compiled_regex> treg;
 
-  gdb_assert (kind <= TYPES_DOMAIN);
+  gdb_assert (m_kind != ALL_DOMAIN);
 
-  ourtype = types[kind];
-  ourtype2 = types2[kind];
-  ourtype3 = types3[kind];
-  ourtype4 = types4[kind];
+  ourtype = types[m_kind];
+  ourtype2 = types2[m_kind];
+  ourtype3 = types3[m_kind];
+  ourtype4 = types4[m_kind];
 
-  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)
        {
@@ -4520,28 +4508,30 @@ 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"));
+      treg.emplace (m_symbol_type_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.  */
+  /* Search through the partial symtabs *first* for all symbols matching
+     the m_symbol_name_regexp (in preg).  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,
+                            return file_matches (filename, filenames,
                                                  basenames);
                           },
                           lookup_name_info::match_any (),
@@ -4552,7 +4542,7 @@ search_symbols (const char *regexp, enum search_domain kind,
                                                    0, NULL, 0) == 0);
                           },
                           NULL,
-                          kind);
+                          m_kind);
 
   /* Here, we search through the minimal symbol tables for functions
      and variables that match, and force their symbols to be read.
@@ -4570,7 +4560,8 @@ search_symbols (const char *regexp, enum search_domain kind,
      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))
+  if (filenames.empty () && (m_kind == VARIABLES_DOMAIN
+                            || m_kind == FUNCTIONS_DOMAIN))
     {
       for (objfile *objfile : current_program_space->objfiles ())
        {
@@ -4587,20 +4578,19 @@ search_symbols (const char *regexp, enum search_domain kind,
                  || MSYMBOL_TYPE (msymbol) == ourtype4)
                {
                  if (!preg.has_value ()
-                     || preg->exec (MSYMBOL_NATURAL_NAME (msymbol), 0,
+                     || preg->exec (msymbol->natural_name (), 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
+                     if (m_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)
+                            (objfile, msymbol->linkage_name (), VAR_DOMAIN)
                             .symbol == NULL))
                        found_misc = 1;
                    }
@@ -4626,16 +4616,16 @@ search_symbols (const char *regexp, enum search_domain kind,
                  /* 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)
+                 if ((file_matches (real_symtab->filename, filenames, false)
                       || ((basenames_may_differ
                            || file_matches (lbasename (real_symtab->filename),
-                                            files, nfiles, 1))
+                                            filenames, true))
                           && file_matches (symtab_to_fullname (real_symtab),
-                                           files, nfiles, 0)))
+                                           filenames, false)))
                      && ((!preg.has_value ()
-                          || preg->exec (SYMBOL_NATURAL_NAME (sym), 0,
+                          || preg->exec (sym->natural_name (), 0,
                                          NULL, 0) == 0)
-                         && ((kind == VARIABLES_DOMAIN
+                         && ((m_kind == VARIABLES_DOMAIN
                               && SYMBOL_CLASS (sym) != LOC_TYPEDEF
                               && SYMBOL_CLASS (sym) != LOC_UNRESOLVED
                               && SYMBOL_CLASS (sym) != LOC_BLOCK
@@ -4648,14 +4638,17 @@ search_symbols (const char *regexp, enum search_domain kind,
                                        == TYPE_CODE_ENUM))
                               && (!treg.has_value ()
                                   || treg_matches_sym_type_name (*treg, sym)))
-                             || (kind == FUNCTIONS_DOMAIN
+                             || (m_kind == FUNCTIONS_DOMAIN
                                  && SYMBOL_CLASS (sym) == LOC_BLOCK
                                  && (!treg.has_value ()
                                      || treg_matches_sym_type_name (*treg,
                                                                     sym)))
-                             || (kind == TYPES_DOMAIN
+                             || (m_kind == TYPES_DOMAIN
                                  && SYMBOL_CLASS (sym) == LOC_TYPEDEF
-                                 && SYMBOL_DOMAIN (sym) != MODULE_DOMAIN))))
+                                 && SYMBOL_DOMAIN (sym) != MODULE_DOMAIN)
+                             || (m_kind == MODULES_DOMAIN
+                                 && SYMBOL_DOMAIN (sym) == MODULE_DOMAIN
+                                 && SYMBOL_LINE (sym) != 0))))
                    {
                      /* match */
                      result.emplace_back (i, sym);
@@ -4668,13 +4661,13 @@ search_symbols (const char *regexp, enum search_domain kind,
   if (!result.empty ())
     sort_search_symbols_remove_dups (&result);
 
-  /* 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.  */
+  /* If there are no debug symbols, then add matching minsyms.  But if the
+     user wants to see symbols matching a type m_symbol_type_regexp, then
+     never give a minimal symbol, as we assume that a minimal symbol does
+     not have a type.  */
 
-  if ((found_misc || (nfiles == 0 && kind != FUNCTIONS_DOMAIN))
-      && !exclude_minsyms
+  if ((found_misc || (filenames.empty () && m_kind != FUNCTIONS_DOMAIN))
+      && !m_exclude_minsyms
       && !treg.has_value ())
     {
       for (objfile *objfile : current_program_space->objfiles ())
@@ -4692,19 +4685,18 @@ search_symbols (const char *regexp, enum search_domain kind,
                  || MSYMBOL_TYPE (msymbol) == ourtype4)
                {
                  if (!preg.has_value ()
-                     || preg->exec (MSYMBOL_NATURAL_NAME (msymbol), 0,
+                     || 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
+                     if (m_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)
+                             (objfile, msymbol->linkage_name (), VAR_DOMAIN)
                              .symbol == NULL)
                            {
                              /* match */
@@ -4720,44 +4712,25 @@ search_symbols (const char *regexp, enum search_domain kind,
   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
@@ -4767,25 +4740,69 @@ print_symbol_info (enum search_domain kind,
         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);
+       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)
+    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
@@ -4811,8 +4828,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
@@ -4826,19 +4842,19 @@ symtab_symbol_info (bool quiet, bool exclude_minsyms,
                    const char *t_regexp, int from_tty)
 {
   static const char * const classnames[] =
-    {"variable", "function", "type"};
+    {"variable", "function", "type", "module"};
   const char *last_filename = "";
   int first = 1;
 
-  gdb_assert (kind <= TYPES_DOMAIN);
+  gdb_assert (kind != ALL_DOMAIN);
 
   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)
     {
@@ -5049,23 +5065,29 @@ info_types_command_completer (struct cmd_list_element *ignore,
   symbol_completer (ignore, tracker, text, word);
 }
 
-/* Breakpoint all functions matching regular expression.  */
+/* Implement the 'info modules' command.  */
 
-void
-rbreak_command_wrapper (char *regexp, int from_tty)
+static void
+info_modules_command (const char *args, int from_tty)
 {
-  rbreak_command (regexp, from_tty);
+  info_types_options opts;
+
+  auto grp = make_info_types_options_def_group (&opts);
+  gdb::option::process_options
+    (&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, grp);
+  if (args != nullptr && *args == '\0')
+    args = nullptr;
+  symtab_symbol_info (opts.quiet, true, args, MODULES_DOMAIN, NULL,
+                     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, ':');
 
@@ -5081,17 +5103,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)
@@ -5102,18 +5121,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 ());
        }
     }
 }
@@ -5183,7 +5202,7 @@ completion_list_add_symbol (completion_tracker &tracker,
                            const char *text, const char *word)
 {
   completion_list_add_name (tracker, SYMBOL_LANGUAGE (sym),
-                           SYMBOL_NATURAL_NAME (sym),
+                           sym->natural_name (),
                            lookup_name, text, word);
 }
 
@@ -5196,7 +5215,7 @@ completion_list_add_msymbol (completion_tracker &tracker,
                             const char *text, const char *word)
 {
   completion_list_add_name (tracker, MSYMBOL_LANGUAGE (sym),
-                           MSYMBOL_NATURAL_NAME (sym),
+                           sym->natural_name (),
                            lookup_name, text, word);
 }
 
@@ -5216,7 +5235,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] != '+'))
@@ -5375,7 +5394,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);
 
@@ -6184,23 +6203,13 @@ 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);
+  SYMBOL_OBJFILE_OWNED (sym) = 1;
+  SYMBOL_SECTION (sym) = -1;
 }
 
 /* Allocate and initialize a new 'struct symbol' on OBJFILE's
@@ -6209,10 +6218,9 @@ initialize_objfile_symbol (struct symbol *sym)
 struct symbol *
 allocate_symbol (struct objfile *objfile)
 {
-  struct symbol *result;
+  struct symbol *result = new (&objfile->objfile_obstack) symbol ();
 
-  result = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct symbol);
-  initialize_objfile_symbol_1 (result);
+  initialize_objfile_symbol (result);
 
   return result;
 }
@@ -6225,8 +6233,8 @@ allocate_template_symbol (struct objfile *objfile)
 {
   struct template_symbol *result;
 
-  result = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct template_symbol);
-  initialize_objfile_symbol_1 (result);
+  result = new (&objfile->objfile_obstack) template_symbol ();
+  initialize_objfile_symbol (result);
 
   return result;
 }
@@ -6276,7 +6284,7 @@ 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 ())
     {
@@ -6285,7 +6293,7 @@ get_symbol_address (const struct symbol *sym)
       if (minsym.minsym != nullptr)
        return BMSYMBOL_VALUE_ADDRESS (minsym);
     }
-  return sym->ginfo.value.address;
+  return sym->value.address;
 }
 
 /* See symtab.h.  */
@@ -6296,7 +6304,7 @@ 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 ())
     {
@@ -6314,6 +6322,314 @@ get_msymbol_address (struct objfile *objf, const struct minimal_symbol *minsym)
 
 \f
 
+/* Hold the sub-commands of 'info module'.  */
+
+static struct cmd_list_element *info_module_cmdlist = NULL;
+
+/* Implement the 'info module' command, just displays some help text for
+   the available sub-commands.  */
+
+static void
+info_module_command (const char *args, int from_tty)
+{
+  help_list (info_module_cmdlist, "info module ", class_info, gdb_stdout);
+}
+
+/* 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)
 {
@@ -6372,6 +6688,49 @@ Options:\n\
   c = add_info ("sources", info_sources_command, info_sources_help.c_str ());
   set_cmd_completer_handle_brkchars (c, info_sources_command_completer);
 
+  c = add_info ("modules", info_modules_command,
+               _("All module names, or those matching REGEXP."));
+  set_cmd_completer_handle_brkchars (c, info_types_command_completer);
+
+  add_prefix_cmd ("module", class_info, info_module_command, _("\
+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.043242 seconds and 4 git commands to generate.