Replace the MSYMBOL_*_NAME macros with member functions
[deliverable/binutils-gdb.git] / gdb / symtab.c
index 160a4c08e961a02350602410cc17082453421e5f..92e8dcdf50c1baa0b4b69f8fe37a193f9a827e85 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");
     }
@@ -723,7 +724,7 @@ struct demangled_name_entry
 
   gdb::string_view mangled;
   enum language language;
-  char demangled[1];
+  gdb::unique_xmalloc_ptr<char> demangled;
 };
 
 /* Hash function for the demangled name hash.  */
@@ -769,10 +770,20 @@ 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));
 }
 
@@ -828,26 +839,24 @@ 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;
-  /* A 0-terminated copy of the linkage name.  */
-  const char *linkage_name_copy;
 
   if (gsymbol->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;
+       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);
@@ -858,20 +867,7 @@ symbol_set_names (struct general_symbol_info *gsymbol,
   if (per_bfd->demangled_names_hash == NULL)
     create_demangled_names_hash (per_bfd);
 
-  if (linkage_name[len] != '\0')
-    {
-      char *alloc_name;
-
-      alloc_name = (char *) alloca (len + 1);
-      memcpy (alloc_name, linkage_name, len);
-      alloc_name[len] = '\0';
-
-      linkage_name_copy = alloc_name;
-    }
-  else
-    linkage_name_copy = linkage_name;
-
-  struct demangled_name_entry entry (gdb::string_view (linkage_name_copy, len));
+  struct demangled_name_entry entry (linkage_name);
   slot = ((struct demangled_name_entry **)
          htab_find_slot (per_bfd->demangled_names_hash.get (),
                          &entry, INSERT));
@@ -880,112 +876,115 @@ symbol_set_names (struct general_symbol_info *gsymbol,
   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[0] == '\0'))
+      || (gsymbol->language == language_go && (*slot)->demangled == nullptr))
     {
-      char *demangled_name_ptr
-       = symbol_find_demangled_name (gsymbol, linkage_name_copy);
-      gdb::unique_xmalloc_ptr<char> demangled_name (demangled_name_ptr);
-      int demangled_len = demangled_name ? strlen (demangled_name.get ()) : 0;
+      /* 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.  */
+      gdb::string_view linkage_name_copy;
+      if (copy_name)
+       {
+         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 = 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.data ()));
 
       /* Suppose we have demangled_name==NULL, copy_name==0, and
         linkage_name_copy==linkage_name.  In this case, we already have the
         mangled name saved, and we don't have a demangled name.  So,
         you might think we could save a little space by not recording
         this in the hash table at all.
-        
+
         It turns out that it is actually important to still save such
         an entry in the hash table, because storing this name gives
         us better bcache hit rates for partial symbols.  */
-      if (!copy_name && linkage_name_copy == linkage_name)
+      if (!copy_name)
        {
          *slot
            = ((struct demangled_name_entry *)
               obstack_alloc (&per_bfd->storage_obstack,
-                             offsetof (struct demangled_name_entry, demangled)
-                             + demangled_len + 1));
-         new (*slot) demangled_name_entry
-           (gdb::string_view (linkage_name, len));
+                             sizeof (demangled_name_entry)));
+         new (*slot) demangled_name_entry (linkage_name);
        }
       else
        {
-         char *mangled_ptr;
-
          /* If we must copy the mangled name, put it directly after
-            the demangled name so we can have a single
-            allocation.  */
+            the struct so we can have a single allocation.  */
          *slot
            = ((struct demangled_name_entry *)
               obstack_alloc (&per_bfd->storage_obstack,
-                             offsetof (struct demangled_name_entry, demangled)
-                             + len + demangled_len + 2));
-         mangled_ptr = &((*slot)->demangled[demangled_len + 1]);
-         strcpy (mangled_ptr, linkage_name_copy);
+                             sizeof (demangled_name_entry)
+                             + linkage_name.length () + 1));
+         char *mangled_ptr = reinterpret_cast<char *> (*slot + 1);
+         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)->language = gsymbol->language;
-
-      if (demangled_name != NULL)
-       strcpy ((*slot)->demangled, demangled_name.get ());
-      else
-       (*slot)->demangled[0] = '\0';
     }
   else if (gsymbol->language == language_unknown
           || gsymbol->language == language_auto)
     gsymbol->language = (*slot)->language;
 
   gsymbol->name = (*slot)->mangled.data ();
-  if ((*slot)->demangled[0] != '\0')
-    symbol_set_demangled_name (gsymbol, (*slot)->demangled,
+  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);
 }
 
-/* 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;
@@ -993,18 +992,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.  */
@@ -1015,7 +1011,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
@@ -1768,7 +1764,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;
 }
@@ -3126,7 +3122,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)
@@ -3732,7 +3728,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);
@@ -4492,7 +4488,7 @@ 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 (kind != ALL_DOMAIN);
 
   ourtype = types[kind];
   ourtype2 = types2[kind];
@@ -4598,7 +4594,7 @@ 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
@@ -4610,8 +4606,7 @@ search_symbols (const char *regexp, enum search_domain kind,
                             (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;
                    }
@@ -4666,7 +4661,10 @@ search_symbols (const char *regexp, enum search_domain kind,
                                                                     sym)))
                              || (kind == TYPES_DOMAIN
                                  && SYMBOL_CLASS (sym) == LOC_TYPEDEF
-                                 && SYMBOL_DOMAIN (sym) != MODULE_DOMAIN))))
+                                 && SYMBOL_DOMAIN (sym) != MODULE_DOMAIN)
+                             || (kind == MODULES_DOMAIN
+                                 && SYMBOL_DOMAIN (sym) == MODULE_DOMAIN
+                                 && SYMBOL_LINE (sym) != 0))))
                    {
                      /* match */
                      result.emplace_back (i, sym);
@@ -4703,7 +4701,7 @@ 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
@@ -4714,8 +4712,7 @@ search_symbols (const char *regexp, enum search_domain kind,
                              == 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 */
@@ -4780,10 +4777,8 @@ print_symbol_info (enum search_domain kind,
       if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_TYPEDEF)
        typedef_print (SYMBOL_TYPE (sym), sym, gdb_stdout);
       else
-       {
-         type_print (SYMBOL_TYPE (sym), "", gdb_stdout, -1);
-         printf_filtered ("\n");
-       }
+       type_print (SYMBOL_TYPE (sym), "", gdb_stdout, -1);
+      printf_filtered ("\n");
     }
   /* variable, func, or typedef-that-is-c++-class.  */
   else if (kind < TYPES_DOMAIN
@@ -4797,6 +4792,11 @@ print_symbol_info (enum search_domain kind,
 
       printf_filtered (";\n");
     }
+  /* 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));
 }
 
 /* This help function for symtab_symbol_info() prints information
@@ -4822,8 +4822,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
@@ -4837,11 +4836,11 @@ 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;
@@ -5060,6 +5059,22 @@ info_types_command_completer (struct cmd_list_element *ignore,
   symbol_completer (ignore, tracker, text, word);
 }
 
+/* Implement the 'info modules' command.  */
+
+static void
+info_modules_command (const char *args, int 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);
+}
+
 /* Breakpoint all functions matching regular expression.  */
 
 void
@@ -5120,11 +5135,11 @@ rbreak_command (const char *regexp, int from_tty)
       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 ());
        }
     }
 }
@@ -5207,7 +5222,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);
 }
 
@@ -5227,7 +5242,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] != '+'))
@@ -6195,23 +6210,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
@@ -6220,10 +6225,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;
 }
@@ -6236,8 +6240,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;
 }
@@ -6296,7 +6300,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.  */
@@ -6307,7 +6311,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 ())
     {
@@ -6325,6 +6329,315 @@ 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.  */
+  std::vector<symbol_search> modules = search_symbols (module_regexp,
+                                                      MODULES_DOMAIN,
+                                                      NULL, 0, NULL,
+                                                      true);
+
+  /* Now search for all symbols of the required KIND matching the required
+     regular expressions.  We figure out which ones are in which modules
+     below.  */
+  std::vector<symbol_search> symbols = search_symbols (regexp, kind,
+                                                      type_regexp, 0,
+                                                      NULL, true);
+
+  /* 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 = SYMBOL_PRINT_NAME (p.symbol);
+      prefix += "::";
+
+      for (const symbol_search &q : symbols)
+       {
+         if (q.symbol == nullptr)
+           continue;
+
+         if (strncmp (SYMBOL_PRINT_NAME (q.symbol), 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"),
+                          SYMBOL_PRINT_NAME (p.symbol));
+         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)
 {
@@ -6383,6 +6696,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.05274 seconds and 4 git commands to generate.