public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCHv3 9/9] gdb/mi: Add -max-results parameter to some -symbol-info-* commands
  2019-10-16 23:28 [PATCHv3 0/9] Fortran 'info module *' commands and MI '-symbol-info-*' commands Andrew Burgess
                   ` (3 preceding siblings ...)
  2019-10-16 23:28 ` [PATCHv3 8/9] gdb/mi: Add -symbol-info-module-{variables,functions} Andrew Burgess
@ 2019-10-16 23:28 ` Andrew Burgess
  2019-10-16 23:28 ` [PATCHv3 2/9] gdb: Add new commands to list module variables and functions Andrew Burgess
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Andrew Burgess @ 2019-10-16 23:28 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

Adds a new parameter -max-results to -symbol-info-functions,
-symbol-info-variables, -symbol-info-types, and -symbol-info-modules.
This parameter limits the number of results returned.

This change still leaves -symbol-info-module-functions and
-symbol-info-module-variables always returning all results, fixing
these commands is slightly harder.

There's currently no mechanism for the user of these commands to know
if the result list has been truncated if you get back the maximum
number of results, so if there are exactly 10 functions and you call
'-symbol-info-functions --max-results 10' the reply would appear no
different than if you had 20 functions and called with a max of 10.
Right now, if you get back the maximum then you should assume that
there might be more results available.

gdb/ChangeLog:

	* mi/mi-symbol-cmds.c (mi_symbol_info): Take extra parameter, and
	add it into the search spec.
	(mi_info_functions_or_variables): Parse -max-results flag and pass
	it to mi_symbol_info.
	(mi_cmd_symbol_info_modules): Likewise.
	(mi_cmd_symbol_info_types): Likewise.
	* symtab.c (symbol_search::compare_search_syms): Update header
	comment.
	(search_symbols_is_suitable_msymbol): New function.
	(search_symbols_expand_symtabs): New function.
	(search_symbols_add_matching_symbols): New function.
	(search_symbols_add_matching_msymbols): New function.
	(search_symbols): Move most of the content into the new functions
	above, and call them as needed.
	* symtab.h (struct search_symbols_spec) <max_search_results>: New
	member variable.

gdb/doc/ChangeLog:

	* doc/gdb.texinfo (GDB/MI Symbol Query): Add documentation of
	-max-results to some -symbol-info-* commands.

gdb/testsuite/ChangeLog:

	* gdb.mi/mi-sym-info.exp: Add tests for -max-results parameter.

Change-Id: I90a28feb55b388fb46461a096c5db08b6b0bd427
---
 gdb/ChangeLog                        |  19 ++
 gdb/doc/ChangeLog                    |   5 +
 gdb/doc/gdb.texinfo                  |  27 ++
 gdb/mi/mi-symbol-cmds.c              |  49 +++-
 gdb/symtab.c                         | 492 ++++++++++++++++++++---------------
 gdb/symtab.h                         |   4 +
 gdb/testsuite/ChangeLog              |   4 +
 gdb/testsuite/gdb.mi/mi-sym-info.exp |  25 ++
 8 files changed, 405 insertions(+), 220 deletions(-)

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 4404c05e225..e40f581e5fe 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -33755,6 +33755,7 @@
  -symbol-info-functions [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
 @end smallexample
 
 @noindent
@@ -33770,6 +33771,11 @@
 to be filtered based on either the name of the function, or the type
 signature of the function.
 
+The option @code{--max-results} restricts the command to return no
+more than @var{limit} results.  If exactly @var{limit} results are
+returned then there might be additional results available if a higher
+limit is used.
+
 @subsubheading @value{GDBN} Command
 
 The corresponding @value{GDBN} command is @samp{info functions}.
@@ -34001,6 +34007,8 @@
 
 @smallexample
  -symbol-info-modules [--name @var{name_regexp}]
+                      [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34011,6 +34019,11 @@
 The option @code{--name} allows the modules returned to be filtered
 based the name of the module.
 
+The option @code{--max-results} restricts the command to return no
+more than @var{limit} results.  If exactly @var{limit} results are
+returned then there might be additional results available if a higher
+limit is used.
+
 @subsubheading @value{GDBN} Command
 
 The corresponding @value{GDBN} command is @samp{info modules}.
@@ -34055,6 +34068,8 @@
 
 @smallexample
  -symbol-info-types [--name @var{name_regexp}]
+                    [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34068,6 +34083,11 @@
 The option @code{--name} allows the list of types returned to be
 filtered by name.
 
+The option @code{--max-results} restricts the command to return no
+more than @var{limit} results.  If exactly @var{limit} results are
+returned then there might be additional results available if a higher
+limit is used.
+
 @subsubheading @value{GDBN} Command
 
 The corresponding @value{GDBN} command is @samp{info types}.
@@ -34115,6 +34135,8 @@
  -symbol-info-variables [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34130,6 +34152,11 @@
 to be filtered based on either the name of the variable, or the type
 of the variable.
 
+The option @code{--max-results} restricts the command to return no
+more than @var{limit} results.  If exactly @var{limit} results are
+returned then there might be additional results available if a higher
+limit is used.
+
 @subsubheading @value{GDBN} Command
 
 The corresponding @value{GDBN} command is @samp{info variables}.
diff --git a/gdb/mi/mi-symbol-cmds.c b/gdb/mi/mi-symbol-cmds.c
index 64f24f6bae5..4aa95909816 100644
--- a/gdb/mi/mi-symbol-cmds.c
+++ b/gdb/mi/mi-symbol-cmds.c
@@ -100,12 +100,14 @@ mi_info_one_symbol_details (enum search_domain kind,
 
 static void
 mi_symbol_info (enum search_domain kind, const char *regexp,
-		const char *t_regexp, bool exclude_minsyms)
+		const char *t_regexp, bool exclude_minsyms,
+		int max_results)
 {
   struct ui_out *uiout = current_uiout;
 
   /* Must make sure that if we're interrupted, symbols gets freed.  */
   search_symbols_spec spec (kind, regexp, t_regexp, exclude_minsyms);
+  spec.max_search_results = max_results;
   std::vector<symbol_search> symbols = search_symbols (spec);
 
   /* The outer container for all the matched symbols.  */
@@ -186,19 +188,21 @@ mi_symbol_info (enum search_domain kind, const char *regexp,
 static void
 mi_info_functions_or_variables (enum search_domain kind, char **argv, int argc)
 {
+  int max_results = -1;	/* -1 for unlimited.  */
   const char *regexp = nullptr;
   const char *t_regexp = nullptr;
   bool exclude_minsyms = true;
 
   enum opt
     {
-     INCLUDE_NONDEBUG_OPT, TYPE_REGEXP_OPT, NAME_REGEXP_OPT
+     INCLUDE_NONDEBUG_OPT, TYPE_REGEXP_OPT, NAME_REGEXP_OPT, MAX_RESULTS_OPT
     };
   static const struct mi_opt opts[] =
   {
     {"-include-nondebug" , INCLUDE_NONDEBUG_OPT, 0},
     {"-type", TYPE_REGEXP_OPT, 1},
     {"-name", NAME_REGEXP_OPT, 1},
+    {"-max-results", MAX_RESULTS_OPT, 1},
     { 0, 0, 0 }
   };
 
@@ -224,10 +228,19 @@ mi_info_functions_or_variables (enum search_domain kind, char **argv, int argc)
 	case NAME_REGEXP_OPT:
 	  regexp = oarg;
 	  break;
+	case MAX_RESULTS_OPT:
+	  {
+	    char *eptr = oarg;
+	    long val = strtol (oarg, &eptr, 10);
+	    if (oarg == eptr || val > INT_MAX || val < 0)
+	      error (_("invalid value for --max-results argument"));
+	    max_results = (int) val;
+	  }
+	  break;
 	}
     }
 
-  mi_symbol_info (kind, regexp, t_regexp, exclude_minsyms);
+  mi_symbol_info (kind, regexp, t_regexp, exclude_minsyms, max_results);
 }
 
 /* Core of -symbol-info-module-functions and -symbol-info-module-variables.
@@ -361,15 +374,17 @@ mi_cmd_symbol_info_module_variables (const char *command, char **argv,
 void
 mi_cmd_symbol_info_modules (const char *command, char **argv, int argc)
 {
+  int max_results = -1; /* -1 for unlimited.  */
   const char *regexp = nullptr;
 
   enum opt
     {
-     NAME_REGEXP_OPT
+     NAME_REGEXP_OPT, MAX_RESULTS_OPT
     };
   static const struct mi_opt opts[] =
   {
     {"-name", NAME_REGEXP_OPT, 1},
+    {"-max-results", MAX_RESULTS_OPT, 1},
     { 0, 0, 0 }
   };
 
@@ -387,10 +402,19 @@ mi_cmd_symbol_info_modules (const char *command, char **argv, int argc)
 	case NAME_REGEXP_OPT:
 	  regexp = oarg;
 	  break;
+	case MAX_RESULTS_OPT:
+	  {
+	    char *eptr = oarg;
+	    long val = strtol (oarg, &eptr, 10);
+	    if (oarg == eptr || val > INT_MAX || val < 0)
+	      error (_("invalid value for --max-results argument"));
+	    max_results = (int) val;
+	  }
+	  break;
 	}
     }
 
-  mi_symbol_info (MODULES_DOMAIN, regexp, nullptr, true);
+  mi_symbol_info (MODULES_DOMAIN, regexp, nullptr, true, max_results);
 }
 
 /* Implement -symbol-info-types command.  */
@@ -398,15 +422,17 @@ mi_cmd_symbol_info_modules (const char *command, char **argv, int argc)
 void
 mi_cmd_symbol_info_types (const char *command, char **argv, int argc)
 {
+  int max_results = -1; /* -1 for unlimited.  */
   const char *regexp = nullptr;
 
   enum opt
     {
-     NAME_REGEXP_OPT
+     NAME_REGEXP_OPT, MAX_RESULTS_OPT
     };
   static const struct mi_opt opts[] =
   {
     {"-name", NAME_REGEXP_OPT, 1},
+    {"-max-results", MAX_RESULTS_OPT, 1},
     { 0, 0, 0 }
   };
 
@@ -424,10 +450,19 @@ mi_cmd_symbol_info_types (const char *command, char **argv, int argc)
 	case NAME_REGEXP_OPT:
 	  regexp = oarg;
 	  break;
+	case MAX_RESULTS_OPT:
+	  {
+	    char *eptr = oarg;
+	    long val = strtol (oarg, &eptr, 10);
+	    if (oarg == eptr || val > INT_MAX || val < 0)
+	      error (_("invalid value for --max-results argument"));
+	    max_results = (int) val;
+	  }
+	  break;
 	}
     }
 
-  mi_symbol_info (TYPES_DOMAIN, regexp, nullptr, true);
+  mi_symbol_info (TYPES_DOMAIN, regexp, nullptr, true, max_results);
 }
 
 /* Implement -symbol-info-variables command.  */
diff --git a/gdb/symtab.c b/gdb/symtab.c
index f7affd418cd..0d8c81af83b 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4351,8 +4351,8 @@ file_matches (const char *file, const std::vector<const char *> &filenames,
   return 0;
 }
 
-/* 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,
@@ -4414,15 +4414,260 @@ treg_matches_sym_type_name (const compiled_regex &treg,
   return treg.exec (printed_sym_type_name.c_str (), 0, NULL, 0) == 0;
 }
 
+/* Return true if MSYMBOL is of type KIND.  */
 
-/* Sort the symbols in RESULT and remove duplicates.  */
+static bool
+search_symbols_is_suitable_msymbol (const enum search_domain kind,
+				    const minimal_symbol *msymbol)
+{
+  static const enum minimal_symbol_type types[]
+    = {mst_data, mst_text};
+  static const enum minimal_symbol_type types2[]
+    = {mst_bss, mst_file_text};
+  static const enum minimal_symbol_type types3[]
+    = {mst_file_data, mst_solib_trampoline};
+  static const enum minimal_symbol_type types4[]
+    = {mst_file_bss, mst_text_gnu_ifunc};
 
-static void
-sort_search_symbols_remove_dups (std::vector<symbol_search> *result)
+  gdb_assert (kind == VARIABLES_DOMAIN || kind == FUNCTIONS_DOMAIN);
+  gdb_assert (kind <= sizeof (types));
+
+  enum minimal_symbol_type ourtype = types[kind];
+  enum minimal_symbol_type ourtype2 = types2[kind];
+  enum minimal_symbol_type ourtype3 = types3[kind];
+  enum minimal_symbol_type ourtype4 = types4[kind];
+
+  return (MSYMBOL_TYPE (msymbol) == ourtype
+	  || MSYMBOL_TYPE (msymbol) == ourtype2
+	  || MSYMBOL_TYPE (msymbol) == ourtype3
+	  || MSYMBOL_TYPE (msymbol) == ourtype4);
+}
+
+/* Expand symtabs in OBJFILE that match SEARCH_SPEC and PREG.  Return true
+   if any msymbols were seen that we should later consider adding to the
+   results list.  */
+
+static bool
+search_symbols_expand_symtabs (objfile *objfile,
+			       const search_symbols_spec &search_spec,
+			       const gdb::optional<compiled_regex> &preg)
 {
-  std::sort (result->begin (), result->end ());
-  result->erase (std::unique (result->begin (), result->end ()),
-		 result->end ());
+  enum search_domain kind = search_spec.kind;
+  bool found_misc = false;
+
+  if (objfile->sf)
+    objfile->sf->qf->expand_symtabs_matching
+      (objfile,
+       [&] (const char *filename, bool basenames)
+       {
+	 /* EXPAND_SYMTABS_MATCHING expects a callback
+	    that returns an integer, not a boolean as
+	    FILE_MATCHES does.  */
+	 return file_matches (filename, search_spec.filenames,
+			      basenames) ? 1 : 0;
+       },
+       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_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 (search_spec.filenames.size () == 0
+      && (kind == VARIABLES_DOMAIN || kind == FUNCTIONS_DOMAIN))
+    {
+      for (minimal_symbol *msymbol : objfile->msymbols ())
+	{
+	  QUIT;
+
+	  if (msymbol->created_by_gdb)
+	    continue;
+
+	  if (search_symbols_is_suitable_msymbol (kind, msymbol))
+	    {
+	      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 = true;
+		}
+	    }
+	}
+    }
+
+  return found_misc;
+}
+
+/* Add symbols from symtabs in OBJFILE that match SEARCH_SPEC, PREG, and
+   TREG to the results set RESULTS_SET.  Return false if we stop adding
+   results early due to having already found too many results (based on
+   max search results limit in SEARCH_SPEC), otherwise return true.  */
+
+static bool
+search_symbols_add_matching_symbols (objfile *objfile,
+				     const search_symbols_spec &search_spec,
+				     const gdb::optional<compiled_regex> &preg,
+				     const gdb::optional<compiled_regex> &treg,
+				     std::set<symbol_search> *result_set)
+{
+  enum search_domain kind = search_spec.kind;
+
+  /* Add matching symbols (if not already present).  */
+  for (compunit_symtab *cust : objfile->compunits ())
+    {
+      const struct blockvector *bv  = COMPUNIT_BLOCKVECTOR (cust);
+
+      for (int i = GLOBAL_BLOCK; i <= STATIC_BLOCK; i++)
+	{
+	  struct block_iterator iter;
+	  struct symbol *sym;
+	  const struct block *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,
+				 search_spec.filenames, false)
+		   || ((basenames_may_differ
+			|| file_matches (lbasename (real_symtab->filename),
+					 search_spec.filenames, true))
+		       && file_matches (symtab_to_fullname (real_symtab),
+					search_spec.filenames, false)))
+		  && ((!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))))
+		{
+		  if (search_spec.max_search_results == -1
+		      || result_set->size () < search_spec.max_search_results)
+		    {
+		      /* Match, insert if not already in the results.  */
+		      symbol_search ss (i, sym);
+		      if (result_set->find (ss) == result_set->end ())
+			result_set->insert (ss);
+		    }
+		  else
+		    return false;
+		}
+	    }
+	}
+    }
+
+  return true;
+}
+
+/* Add msymbols from OBJFILE that match SEARCH_SPEC and PREG, to the
+   results vector RESULTS.  Return false if we stop adding results early
+   due to having already found too many results (based on max search
+   results limit in SEARCH_SPEC), otherwise return true.  */
+
+static bool
+search_symbols_add_matching_msymbols (objfile *objfile,
+				      const search_symbols_spec &search_spec,
+				      const gdb::optional<compiled_regex> &preg,
+				      std::vector<symbol_search> *results)
+{
+  enum search_domain kind = search_spec.kind;
+
+  for (minimal_symbol *msymbol : objfile->msymbols ())
+    {
+      QUIT;
+
+      if (msymbol->created_by_gdb)
+	continue;
+
+      if (search_symbols_is_suitable_msymbol (kind, msymbol))
+	{
+	  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)
+		    {
+		      /* Matching msymbol, add it to the results list.  */
+		      if (search_spec.max_search_results == -1
+			  || (results->size ()
+			      < search_spec.max_search_results))
+			{
+			  results->emplace_back (GLOBAL_BLOCK, msymbol,
+						 objfile);
+			}
+		      else
+			return false;
+		    }
+		}
+	    }
+	}
+    }
+
+  return true;
 }
 
 /* See symtab.h.  */
@@ -4434,39 +4679,13 @@ search_symbols (const search_symbols_spec &search_spec)
   const char *regexp = search_spec.symbol_regexp;
   enum search_domain kind = search_spec.kind;
   const char *t_regexp = search_spec.type_regexp;
-  int nfiles = search_spec.filenames.size ();
-  bool exclude_minsyms = search_spec.exclude_minsyms;
 
   /* The search.  */
-  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 <= MODULES_DOMAIN);
 
-  ourtype = types[kind];
-  ourtype2 = types2[kind];
-  ourtype3 = types3[kind];
-  ourtype4 = types4[kind];
-
   if (regexp != NULL)
     {
       /* Make sure spacing is right for C++ operators.
@@ -4515,193 +4734,40 @@ search_symbols (const search_symbols_spec &search_spec)
       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)
-			   {
-			     /* EXPAND_SYMTABS_MATCHING expects a callback
-				that returns an integer, not a boolean as
-				FILE_MATCHES does.  */
-			     return file_matches (filename,
-						  search_spec.filenames,
-						  basenames) ? 1 : 0;
-			   },
-			   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;
-		    }
-		}
-	    }
-	}
-    }
-
+  bool found_misc = 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,
-				     search_spec.filenames, false)
-		       || ((basenames_may_differ
-			    || file_matches (lbasename (real_symtab->filename),
-					     search_spec.filenames, true))
-			   && file_matches (symtab_to_fullname (real_symtab),
-					    search_spec.filenames, false)))
-		      && ((!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_misc
+	|= search_symbols_expand_symtabs (objfile, search_spec, preg);
 
-  if (!result.empty ())
-    sort_search_symbols_remove_dups (&result);
+      /* Find matching symbols within OBJFILE and add them in to
+	 RESULT_SET.  */
+      if (!search_symbols_add_matching_symbols (objfile, search_spec, 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.  */
+  std::vector<symbol_search> result (result_set.begin (), result_set.end ());
+  std::sort (result.begin (), result.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_misc || (search_spec.filenames.size () == 0
+		      && kind == VARIABLES_DOMAIN))
+      && !search_spec.exclude_minsyms
       && !treg.has_value ())
     {
+      gdb_assert (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)
-		    {
-		      /* 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 (!search_symbols_add_matching_msymbols (objfile, search_spec,
+						   preg, &result))
+	  break;
     }
 
   return result;
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 8852b50a170..b4c58a0074c 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -2090,6 +2090,10 @@ struct search_symbols_spec
   /* The set of source files to search in for matching symbols.  */
   std::vector<const char *> filenames;
 
+  /* Maximum number of search results, set to -1 for unlimited, otherwise
+     set to a positive value to limit the number of results returned.  */
+  int max_search_results = -1;
+
   /* Constructor.  */
   search_symbols_spec (enum search_domain kind,
 		       const char *symbol_regexp = nullptr,
diff --git a/gdb/testsuite/gdb.mi/mi-sym-info.exp b/gdb/testsuite/gdb.mi/mi-sym-info.exp
index 33fe8657811..80468a47502 100644
--- a/gdb/testsuite/gdb.mi/mi-sym-info.exp
+++ b/gdb/testsuite/gdb.mi/mi-sym-info.exp
@@ -127,3 +127,28 @@ set lineno2 [gdb_get_line_number "typedef int another_int_t;" ${srcfile2}]
 mi_gdb_test "120-symbol-info-types --name _int_" \
     "120\\^done,symbols=\{debug=\\\[\{filename=\"\[^\"\]+$srcfile\",fullname=\"\[^\"\]+$srcfile\",symbols=\\\[\{line=\"27\",name=\"my_int_t\"\}\\\]\},\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"23\",name=\"another_int_t\"\}\\\]\}\\\]\}" \
     "List all types matching _int_"
+
+# Test the --max-results parameter.
+mi_gdb_test "121-symbol-info-functions --max-results 0" \
+    "121\\^done,symbols=\{\}" \
+    "-symbol-info-functions --max-results 0"
+
+mi_gdb_test "122-symbol-info-functions --max-results 1" \
+    "122\\^done,symbols=\{debug=\\\[\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"39\",name=\"f3\",type=\"int \\(another_int_t\\)\",description=\"int f3\\(another_int_t\\);\"\}\\\]\}\\\]\}" \
+    "-symbol-info-functions --max-results 1"
+
+mi_gdb_test "123-symbol-info-functions --max-results 2" \
+    "123\\^done,symbols=\{debug=\\\[\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"33\",name=\"f2\",type=\"float \\(another_float_t\\)\",description=\"float f2\\(another_float_t\\);\"\},\{line=\"39\",name=\"f3\",type=\"int \\(another_int_t\\)\",description=\"int f3\\(another_int_t\\);\"\}\\\]\}\\\]\}" \
+    "-symbol-info-functions --max-results 2"
+
+mi_gdb_test "124-symbol-info-variables --max-results 3" \
+    "124\\^done,symbols=\{debug=\\\[\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"21\",name=\"global_f2\",type=\"int\",description=\"int global_f2;\"\},\{line=\"20\",name=\"global_i2\",type=\"int\",description=\"int global_i2;\"\},\{line=\"19\",name=\"global_f1\",type=\"float\",description=\"static float global_f1;\"\}\\\]\}\\\]\}" \
+    "-symbol-info-variables --max-results 3"
+
+mi_gdb_test "125-symbol-info-types --max-results 4" \
+    "125\\^done,symbols=\{debug=\\\[\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"24\",name=\"another_float_t\"\},\{line=\"23\",name=\"another_int_t\"\},\{name=\"float\"\},\{name=\"int\"\}\\\]\}\\\]\}" \
+    "-symbol-info-types --max-results 4"
+
+
+
+
-- 
2.14.5

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCHv3 6/9] gdb/mi: Add new commands -symbol-info-{functions,variables,types}
  2019-10-16 23:28 [PATCHv3 0/9] Fortran 'info module *' commands and MI '-symbol-info-*' commands Andrew Burgess
  2019-10-16 23:28 ` [PATCHv3 4/9] gdb: Introduce symbol_search_spec Andrew Burgess
@ 2019-10-16 23:28 ` Andrew Burgess
  2019-10-16 23:28 ` [PATCHv3 7/9] gdb/mi: Add -symbol-info-modules command Andrew Burgess
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Andrew Burgess @ 2019-10-16 23:28 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

Add new MI commands -symbol-info-functions, -symbol-info-variables,
and -symbol-info-types which correspond to the CLI commands 'info
functions', 'info variables', and 'info types' respectively.

gdb/ChangeLog:

	* mi/mi-cmds.c (mi_cmds): Add '-symbol-info-functions',
	'-symbol-info-variables', and '-symbol-info-types'.
	* mi/mi-cmds.h (mi_cmd_symbol_info_functions): Declare.
	(mi_cmd_symbol_info_variables): Declare.
	(mi_cmd_symbol_info_types): Declare.
	* mi/mi-symbol-cmds.c: Add 'source.h' and 'mi-getopt.h' includes.
	(mi_symbol_info): New function.
	(mi_info_functions_or_variables): New function.
	(mi_cmd_symbol_info_functions): New function.
	(mi_cmd_symbol_info_variables): New function.
	(mi_cmd_symbol_info_types): New function.
	* NEWS: Mention new commands.

gdb/testsuite/ChangeLog:

	* gdb.mi/mi-sym-info-1.c: New file.
	* gdb.mi/mi-sym-info-2.c: New file.
	* gdb.mi/mi-sym-info.exp: New file.

gdb/doc/ChangeLog:

	* doc/gdb.texinfo (GDB/MI Symbol Query): Document new MI command
	-symbol-info-functions, -symbol-info-types, and
	-symbol-info-variables.

Change-Id: Ic2fc6a6750bbce91cdde2344791014e5ef45642d
---
 gdb/ChangeLog                        |  15 ++
 gdb/NEWS                             |   4 +
 gdb/doc/ChangeLog                    |   6 +
 gdb/doc/gdb.texinfo                  | 268 ++++++++++++++++++++++++++++++++++-
 gdb/mi/mi-cmds.c                     |   3 +
 gdb/mi/mi-cmds.h                     |   3 +
 gdb/mi/mi-symbol-cmds.c              | 224 +++++++++++++++++++++++++++++
 gdb/testsuite/ChangeLog              |   6 +
 gdb/testsuite/gdb.mi/mi-sym-info-1.c |  48 +++++++
 gdb/testsuite/gdb.mi/mi-sym-info-2.c |  43 ++++++
 gdb/testsuite/gdb.mi/mi-sym-info.exp | 129 +++++++++++++++++
 11 files changed, 743 insertions(+), 6 deletions(-)
 create mode 100644 gdb/testsuite/gdb.mi/mi-sym-info-1.c
 create mode 100644 gdb/testsuite/gdb.mi/mi-sym-info-2.c
 create mode 100644 gdb/testsuite/gdb.mi/mi-sym-info.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index 276e9618afa..81ad7f26bfb 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -332,6 +332,10 @@ focus, winheight, +, -, >, <
   These can be used to catch C++ exceptions in a similar fashion to
   the CLI commands 'catch throw', 'catch rethrow', and 'catch catch'.
 
+-symbol-info-functions, -symbol-info-types, and -symbol-info-variables
+  These commands are the MI equivalent of the CLI commands 'info
+  functions', 'info types', and 'info variables' respectively.
+
 * Other MI changes
 
  ** The default version of the MI interpreter is now 3 (-i=mi3).
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index c05955cbb68..57bcde19894 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -33743,27 +33743,283 @@
 
 @subsubheading Example
 N.A.
+@end ignore
+
+@subheading The @code{-symbol-info-functions} Command
+@findex -symbol-info-functions
+@anchor{-symbol-info-functions}
+
+@subsubheading Synopsis
+
+@smallexample
+ -symbol-info-functions [--include-nondebug]
+                        [--type @var{type_regexp}]
+                        [--name @var{name_regexp}]
+@end smallexample
+
+@noindent
+Return a list containing the names and types for all global functions
+taken from the debug information.  The functions are grouped by source
+file, and shown with the line number on which each function is
+defined.
 
+The @code{--include-nondebug} option causes the output to include
+code symbols from the symbol table.
+
+The options @code{--type} and @code{--name} allow the symbols returned
+to be filtered based on either the name of the function, or the type
+signature of the function.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{info functions}.
+
+@subsubheading Example
+@smallexample
+@group
+(gdb)
+-symbol-info-functions
+^done,symbols=
+  @{debug=
+    [@{filename="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      symbols=[@{line="36", name="f4", type="void (int *)",
+                description="void f4(int *);"@},
+               @{line="42", name="main", type="int ()",
+                description="int main();"@},
+               @{line="30", name="f1", type="my_int_t (int, int)",
+                description="static my_int_t f1(int, int);"@}]@},
+     @{filename="/project/gdb/testsuite/gdb.mi/mi-sym-info-2.c",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-2.c",
+      symbols=[@{line="33", name="f2", type="float (another_float_t)",
+                description="float f2(another_float_t);"@},
+               @{line="39", name="f3", type="int (another_int_t)",
+                description="int f3(another_int_t);"@},
+               @{line="27", name="f1", type="another_float_t (int)",
+                description="static another_float_t f1(int);"@}]@}]@}
+@end group
+@group
+(gdb)
+-symbol-info-functions --name f1
+^done,symbols=
+  @{debug=
+    [@{filename="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      symbols=[@{line="30", name="f1", type="my_int_t (int, int)",
+                description="static my_int_t f1(int, int);"@}]@},
+     @{filename="/project/gdb/testsuite/gdb.mi/mi-sym-info-2.c",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-2.c",
+      symbols=[@{line="27", name="f1", type="another_float_t (int)",
+                description="static another_float_t f1(int);"@}]@}]@}
+@end group
+@group
+(gdb)
+-symbol-info-functions --type void
+^done,symbols=
+  @{debug=
+    [@{filename="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      symbols=[@{line="36", name="f4", type="void (int *)",
+                description="void f4(int *);"@}]@}]@}
+@end group
+@group
+(gdb)
+-symbol-info-functions --include-nondebug
+^done,symbols=
+  @{debug=
+    [@{filename="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      symbols=[@{line="36", name="f4", type="void (int *)",
+                description="void f4(int *);"@},
+               @{line="42", name="main", type="int ()",
+                description="int main();"@},
+               @{line="30", name="f1", type="my_int_t (int, int)",
+                description="static my_int_t f1(int, int);"@}]@},
+     @{filename="/project/gdb/testsuite/gdb.mi/mi-sym-info-2.c",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-2.c",
+      symbols=[@{line="33", name="f2", type="float (another_float_t)",
+                description="float f2(another_float_t);"@},
+               @{line="39", name="f3", type="int (another_int_t)",
+                description="int f3(another_int_t);"@},
+               @{line="27", name="f1", type="another_float_t (int)",
+                description="static another_float_t f1(int);"@}]@}],
+   nondebug=
+    [@{address="0x0000000000400398",name="_init"@},
+     @{address="0x00000000004003b0",name="_start"@},
+      ...
+    ]@}
+@end group
+@end smallexample
 
-@subheading The @code{-symbol-info-function} Command
-@findex -symbol-info-function
+@subheading The @code{-symbol-info-types} Command
+@findex -symbol-info-types
+@anchor{-symbol-info-types}
 
 @subsubheading Synopsis
 
 @smallexample
- -symbol-info-function
+ -symbol-info-types [--name @var{name_regexp}]
 @end smallexample
 
-Show which function the symbol lives in.
+@noindent
+Return a list of all defined types.  The types are grouped by source
+file, and shown with the line number on which each user defined type
+is defined.  Some base types are not defined in the source code but
+are added to the debug information by the compiler, for example
+@code{int}, @code{float}, etc.; these types do not have an associated
+line number.
+
+The option @code{--name} allows the list of types returned to be
+filtered by name.
 
 @subsubheading @value{GDBN} Command
 
-@samp{gdb_get_function} in @code{gdbtk}.
+The corresponding @value{GDBN} command is @samp{info types}.
 
 @subsubheading Example
-N.A.
+@smallexample
+@group
+(gdb)
+-symbol-info-types
+^done,symbols=
+  @{debug=
+     [@{filename="gdb.mi/mi-sym-info-1.c",
+       fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+       symbols=[@{name="float"@},
+                @{name="int"@},
+                @{line="27",name="typedef int my_int_t;"@}]@},
+      @{filename="gdb.mi/mi-sym-info-2.c",
+       fullname="/project/gdb.mi/mi-sym-info-2.c",
+       symbols=[@{line="24",name="typedef float another_float_t;"@},
+                @{line="23",name="typedef int another_int_t;"@},
+                @{name="float"@},
+                @{name="int"@}]@}]@}
+@end group
+@group
+(gdb)
+-symbol-info-types --name _int_
+^done,symbols=
+  @{debug=
+     [@{filename="gdb.mi/mi-sym-info-1.c",
+       fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+       symbols=[@{line="27",name="typedef int my_int_t;"@}]@},
+      @{filename="gdb.mi/mi-sym-info-2.c",
+       fullname="/project/gdb.mi/mi-sym-info-2.c",
+       symbols=[@{line="23",name="typedef int another_int_t;"@}]@}]@}
+@end group
+@end smallexample
+
+@subheading The @code{-symbol-info-variables} Command
+@findex -symbol-info-variables
+@anchor{-symbol-info-variables}
+
+@subsubheading Synopsis
+
+@smallexample
+ -symbol-info-variables [--include-nondebug]
+                        [--type @var{type_regexp}]
+                        [--name @var{name_regexp}]
+@end smallexample
+
+@noindent
+Return a list containing the names and types for all global variables
+taken from the debug information.  The variables are grouped by source
+file, and shown with the line number on which each variable is
+defined.
+
+The @code{--include-nondebug} option causes the output to include
+data symbols from the symbol table.
+
+The options @code{--type} and @code{--name} allow the symbols returned
+to be filtered based on either the name of the variable, or the type
+of the variable.
+
+@subsubheading @value{GDBN} Command
 
+The corresponding @value{GDBN} command is @samp{info variables}.
 
+@subsubheading Example
+@smallexample
+@group
+(gdb)
+-symbol-info-variables
+^done,symbols=
+  @{debug=
+    [@{filename="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      symbols=[@{line="25",name="global_f1",type="float",
+                description="static float global_f1;"@},
+               @{line="24",name="global_i1",type="int",
+                description="static int global_i1;"@}]@},
+     @{filename="/project/gdb/testsuite/gdb.mi/mi-sym-info-2.c",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-2.c",
+      symbols=[@{line="21",name="global_f2",type="int",
+                description="int global_f2;"@},
+               @{line="20",name="global_i2",type="int",
+                description="int global_i2;"@},
+               @{line="19",name="global_f1",type="float",
+                description="static float global_f1;"@},
+               @{line="18",name="global_i1",type="int",
+                description="static int global_i1;"@}]@}]@}
+@end group
+@group
+(gdb)
+-symbol-info-variables --name f1
+^done,symbols=
+  @{debug=
+    [@{filename="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      symbols=[@{line="25",name="global_f1",type="float",
+                description="static float global_f1;"@}]@},
+     @{filename="/project/gdb/testsuite/gdb.mi/mi-sym-info-2.c",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-2.c",
+      symbols=[@{line="19",name="global_f1",type="float",
+                description="static float global_f1;"@}]@}]@}
+@end group
+@group
+(gdb)
+-symbol-info-variables --type float
+^done,symbols=
+  @{debug=
+    [@{filename="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      symbols=[@{line="25",name="global_f1",type="float",
+                description="static float global_f1;"@}]@},
+     @{filename="/project/gdb/testsuite/gdb.mi/mi-sym-info-2.c",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-2.c",
+      symbols=[@{line="19",name="global_f1",type="float",
+                description="static float global_f1;"@}]@}]@}
+@end group
+@group
+(gdb)
+-symbol-info-variables --include-nondebug
+^done,symbols=
+  @{debug=
+    [@{filename="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      symbols=[@{line="25",name="global_f1",type="float",
+                description="static float global_f1;"@},
+               @{line="24",name="global_i1",type="int",
+                description="static int global_i1;"@}]@},
+     @{filename="/project/gdb/testsuite/gdb.mi/mi-sym-info-2.c",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-2.c",
+      symbols=[@{line="21",name="global_f2",type="int",
+                description="int global_f2;"@},
+               @{line="20",name="global_i2",type="int",
+                description="int global_i2;"@},
+               @{line="19",name="global_f1",type="float",
+                description="static float global_f1;"@},
+               @{line="18",name="global_i1",type="int",
+                description="static int global_i1;"@}]@}],
+   nondebug=
+    [@{address="0x00000000004005d0",name="_IO_stdin_used"@},
+     @{address="0x00000000004005d8",name="__dso_handle"@}
+      ...
+    ]@}
+@end group
+@end smallexample
+
+@ignore
 @subheading The @code{-symbol-info-line} Command
 @findex -symbol-info-line
 
diff --git a/gdb/mi/mi-cmds.c b/gdb/mi/mi-cmds.c
index 37eab01de9e..df9f25fcbd0 100644
--- a/gdb/mi/mi-cmds.c
+++ b/gdb/mi/mi-cmds.c
@@ -151,6 +151,9 @@ static struct mi_cmd mi_cmds[] =
   DEF_MI_CMD_MI_1 ("stack-select-frame", mi_cmd_stack_select_frame,
 		   &mi_suppress_notification.user_selected_context),
   DEF_MI_CMD_MI ("symbol-list-lines", mi_cmd_symbol_list_lines),
+  DEF_MI_CMD_MI ("symbol-info-functions", mi_cmd_symbol_info_functions),
+  DEF_MI_CMD_MI ("symbol-info-variables", mi_cmd_symbol_info_variables),
+  DEF_MI_CMD_MI ("symbol-info-types", mi_cmd_symbol_info_types),
   DEF_MI_CMD_CLI ("target-attach", "attach", 1),
   DEF_MI_CMD_MI ("target-detach", mi_cmd_target_detach),
   DEF_MI_CMD_CLI ("target-disconnect", "disconnect", 0),
diff --git a/gdb/mi/mi-cmds.h b/gdb/mi/mi-cmds.h
index 91ce4cd4070..c2fd7d30d63 100644
--- a/gdb/mi/mi-cmds.h
+++ b/gdb/mi/mi-cmds.h
@@ -94,6 +94,9 @@ extern mi_cmd_argv_ftype mi_cmd_stack_list_locals;
 extern mi_cmd_argv_ftype mi_cmd_stack_list_variables;
 extern mi_cmd_argv_ftype mi_cmd_stack_select_frame;
 extern mi_cmd_argv_ftype mi_cmd_symbol_list_lines;
+extern mi_cmd_argv_ftype mi_cmd_symbol_info_functions;
+extern mi_cmd_argv_ftype mi_cmd_symbol_info_types;
+extern mi_cmd_argv_ftype mi_cmd_symbol_info_variables;
 extern mi_cmd_argv_ftype mi_cmd_target_detach;
 extern mi_cmd_argv_ftype mi_cmd_target_file_get;
 extern mi_cmd_argv_ftype mi_cmd_target_file_put;
diff --git a/gdb/mi/mi-symbol-cmds.c b/gdb/mi/mi-symbol-cmds.c
index 63142e8e7e9..6b0aa9538f5 100644
--- a/gdb/mi/mi-symbol-cmds.c
+++ b/gdb/mi/mi-symbol-cmds.c
@@ -21,6 +21,8 @@
 #include "symtab.h"
 #include "objfiles.h"
 #include "ui-out.h"
+#include "source.h"
+#include "mi-getopt.h"
 
 /* Print the list of all pc addresses and lines of code for the
    provided (full or base) source file name.  The entries are sorted
@@ -59,3 +61,225 @@ mi_cmd_symbol_list_lines (const char *command, char **argv, int argc)
       uiout->field_signed ("line", SYMTAB_LINETABLE (s)->item[i].line);
     }
 }
+
+/* Used by the -symbol-info-* and -symbol-info-module-* commands to print
+   information about the symbol SYM in a block of index BLOCK (either
+   GLOBAL_BLOCK or STATIC_BLOCK).  KIND is the kind of symbol we searched
+   for in order to find SYM, which impact which fields are displayed in the
+   results.  */
+
+static void
+mi_info_one_symbol_details (enum search_domain kind,
+			    struct symbol *sym, int block)
+{
+  struct ui_out *uiout = current_uiout;
+
+  ui_out_emit_tuple tuple_emitter (uiout, NULL);
+  if (SYMBOL_LINE (sym) != 0)
+    uiout->field_unsigned ("line", SYMBOL_LINE (sym));
+  uiout->field_string ("name", SYMBOL_PRINT_NAME (sym));
+
+  if (kind == FUNCTIONS_DOMAIN || kind == VARIABLES_DOMAIN)
+    {
+      string_file tmp_stream;
+      type_print (SYMBOL_TYPE (sym), "", &tmp_stream, -1);
+      uiout->field_string ("type", tmp_stream.string ());
+
+      std::string str = symbol_to_info_string (sym, block, kind);
+      uiout->field_string ("description", str.c_str ());
+    }
+}
+
+/* This is the guts of the commands '-symbol-info-functions',
+   '-symbol-info-variables', and '-symbol-info-types'.  It calls
+   search_symbols to find all matches and then prints the matching
+   [m]symbols in an MI structured format.  This is similar to
+   symtab_symbol_info in symtab.c.  All the arguments are used to
+   initialise a SEARCH_SYMBOLS_SPEC, see symtab.h for a description of
+   their meaning.  */
+
+static void
+mi_symbol_info (enum search_domain kind, const char *regexp,
+		const char *t_regexp, bool exclude_minsyms)
+{
+  struct ui_out *uiout = current_uiout;
+
+  /* Must make sure that if we're interrupted, symbols gets freed.  */
+  search_symbols_spec spec (kind, regexp, t_regexp, exclude_minsyms);
+  std::vector<symbol_search> symbols = search_symbols (spec);
+
+  /* The outer container for all the matched symbols.  */
+  ui_out_emit_tuple all_matching_symbols (uiout, "symbols");
+
+  /* The order of these optional emitters is critical as they will be
+     deleted in reverse order, which is important as these are popped from
+     the uiout stack as they are destroyed.  */
+  gdb::optional<ui_out_emit_list> debug_func_emitter_outer;
+  gdb::optional<ui_out_emit_tuple> debug_func_emitter_symtab;
+  gdb::optional<ui_out_emit_list> debug_func_emitter_symbols;
+  gdb::optional<ui_out_emit_list> nondebug_func_emitter;
+
+  const symtab *last_symtab = nullptr;
+
+  for (const symbol_search &p : symbols)
+    {
+      QUIT;
+
+      if (p.msymbol.minsym != NULL)
+	{
+	  if (debug_func_emitter_outer.has_value ())
+	    {
+	      gdb_assert (debug_func_emitter_symbols.has_value ());
+	      gdb_assert (debug_func_emitter_symtab.has_value ());
+	      debug_func_emitter_symbols.reset ();
+	      debug_func_emitter_symtab.reset ();
+	      debug_func_emitter_outer.reset ();
+	    }
+
+	  if (!nondebug_func_emitter.has_value ())
+	    nondebug_func_emitter.emplace (uiout, "nondebug");
+	  struct bound_minimal_symbol msymbol = p.msymbol;
+	  struct gdbarch *gdbarch = get_objfile_arch (msymbol.objfile);
+	  ui_out_emit_tuple tuple_emitter (uiout, NULL);
+	  uiout->field_core_addr ("address", gdbarch,
+				  BMSYMBOL_VALUE_ADDRESS (msymbol));
+	  uiout->field_string ("name", MSYMBOL_PRINT_NAME (msymbol.minsym));
+	}
+      else
+	{
+	  struct symbol *sym = p.symbol;
+	  struct symtab *s = symbol_symtab (sym);
+
+	  /* All debug symbols should appear in the list before all
+	     non-debug symbols.  */
+	  gdb_assert (!nondebug_func_emitter.has_value ());
+
+	  /* Start the list of debug symbols.  */
+	  if (!debug_func_emitter_outer.has_value ())
+	    debug_func_emitter_outer.emplace (uiout, "debug");
+
+	  if (s != last_symtab)
+	    {
+	      /* Reset a possible previous symbol list within a symtab.  */
+	      debug_func_emitter_symbols.reset ();
+	      debug_func_emitter_symtab.reset ();
+
+	      /* Start a new symtab and symbol list within the symtab.  */
+	      debug_func_emitter_symtab.emplace (uiout, nullptr);
+	      uiout->field_string ("filename",
+				   symtab_to_filename_for_display (s));
+	      uiout->field_string ("fullname", symtab_to_fullname (s));
+	      debug_func_emitter_symbols.emplace (uiout, "symbols");
+
+	      /* Record the current symtab.  */
+	      last_symtab = s;
+	    }
+
+	  mi_info_one_symbol_details (kind, sym, p.block);
+	}
+    }
+}
+
+/* Helper for mi_cmd_symbol_info_{functions,variables} - depending on KIND.
+   Processes command line options from ARGV and ARGC.  */
+
+static void
+mi_info_functions_or_variables (enum search_domain kind, char **argv, int argc)
+{
+  const char *regexp = nullptr;
+  const char *t_regexp = nullptr;
+  bool exclude_minsyms = true;
+
+  enum opt
+    {
+     INCLUDE_NONDEBUG_OPT, TYPE_REGEXP_OPT, NAME_REGEXP_OPT
+    };
+  static const struct mi_opt opts[] =
+  {
+    {"-include-nondebug" , INCLUDE_NONDEBUG_OPT, 0},
+    {"-type", TYPE_REGEXP_OPT, 1},
+    {"-name", NAME_REGEXP_OPT, 1},
+    { 0, 0, 0 }
+  };
+
+  int oind = 0;
+  char *oarg = nullptr;
+
+  while (1)
+    {
+      const char *cmd_string
+	= ((kind == FUNCTIONS_DOMAIN)
+	   ? "-symbol-info-functions" : "-symbol-info-variables");
+      int opt = mi_getopt (cmd_string, argc, argv, opts, &oind, &oarg);
+      if (opt < 0)
+	break;
+      switch ((enum opt) opt)
+	{
+	case INCLUDE_NONDEBUG_OPT:
+	  exclude_minsyms = false;
+	  break;
+	case TYPE_REGEXP_OPT:
+	  t_regexp = oarg;
+	  break;
+	case NAME_REGEXP_OPT:
+	  regexp = oarg;
+	  break;
+	}
+    }
+
+  mi_symbol_info (kind, regexp, t_regexp, exclude_minsyms);
+}
+
+/* Implement -symbol-info-functions command.  */
+
+void
+mi_cmd_symbol_info_functions (const char *command, char **argv, int argc)
+{
+  mi_info_functions_or_variables (FUNCTIONS_DOMAIN, argv, argc);
+}
+
+/* Implement -symbol-info-types command.  */
+
+void
+mi_cmd_symbol_info_types (const char *command, char **argv, int argc)
+{
+  const char *regexp = nullptr;
+
+  enum opt
+    {
+     NAME_REGEXP_OPT
+    };
+  static const struct mi_opt opts[] =
+  {
+    {"-name", NAME_REGEXP_OPT, 1},
+    { 0, 0, 0 }
+  };
+
+  int oind = 0;
+  char *oarg = nullptr;
+
+  while (1)
+    {
+      int opt = mi_getopt ("-symbol-info-types", argc, argv, opts,
+			   &oind, &oarg);
+      if (opt < 0)
+	break;
+      switch ((enum opt) opt)
+	{
+	case NAME_REGEXP_OPT:
+	  regexp = oarg;
+	  break;
+	}
+    }
+
+  mi_symbol_info (TYPES_DOMAIN, regexp, nullptr, true);
+}
+
+/* Implement -symbol-info-variables command.  */
+
+void
+mi_cmd_symbol_info_variables (const char *command, char **argv, int argc)
+{
+  mi_info_functions_or_variables (VARIABLES_DOMAIN, argv, argc);
+}
+
diff --git a/gdb/testsuite/gdb.mi/mi-sym-info-1.c b/gdb/testsuite/gdb.mi/mi-sym-info-1.c
new file mode 100644
index 00000000000..9b6dc7396ad
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-sym-info-1.c
@@ -0,0 +1,48 @@
+/* Copyright 2019 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Function and variables declared in mi-sym-info-2.c.  */
+extern float f2 (float arg);
+extern int f3 (int arg);
+extern int global_i2;
+extern float global_f2;
+
+static int global_i1;
+static float global_f1;
+
+typedef int my_int_t;
+
+static my_int_t
+f1 (int arg1, int arg2)
+{
+  return arg1 + arg2;
+}
+
+void
+f4 (int *arg)
+{
+  (*arg)++;
+}
+
+int
+main ()
+{
+  int v = f3 (4);
+  f4 (&v);
+  float tmp = f2 (1.0);
+  return f1 (3, v) + ((int) tmp);
+}
diff --git a/gdb/testsuite/gdb.mi/mi-sym-info-2.c b/gdb/testsuite/gdb.mi/mi-sym-info-2.c
new file mode 100644
index 00000000000..c80877d8e7b
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-sym-info-2.c
@@ -0,0 +1,43 @@
+/* Copyright 2019 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+static int global_i1;
+static float global_f1;
+int global_i2;
+int global_f2;
+
+typedef int another_int_t;
+typedef float another_float_t;
+
+static another_float_t
+f1 (int arg)
+{
+  return (float) arg;
+}
+
+float
+f2 (another_float_t arg)
+{
+  return arg + f1 (1);
+}
+
+int
+f3 (another_int_t arg)
+{
+  return arg + 2;
+}
+
diff --git a/gdb/testsuite/gdb.mi/mi-sym-info.exp b/gdb/testsuite/gdb.mi/mi-sym-info.exp
new file mode 100644
index 00000000000..33fe8657811
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-sym-info.exp
@@ -0,0 +1,129 @@
+# Copyright 2019 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test -symbol-info-functions, -symbol-info-variables, and
+# -symbol-info-types.
+
+load_lib mi-support.exp
+set MIFLAGS "-i=mi"
+
+standard_testfile mi-sym-info-1.c mi-sym-info-2.c
+
+if {[prepare_for_testing "failed to prepare" ${testfile} \
+	 [list $srcfile $srcfile2] {debug}]} {
+    return -1
+}
+
+gdb_exit
+if {[mi_gdb_start]} {
+    continue
+}
+
+mi_run_to_main
+
+set qstr "\"\[^\"\]+\""
+set fun_re "\{line=\"$decimal\",name=${qstr},type=${qstr},description=${qstr}\}"
+set type_re "\{(?:line=\"$decimal\",)*name=${qstr}\}"
+set sym_list "\\\[${fun_re}(?:,$fun_re)*\\\]"
+set type_sym_list "\\\[${type_re}(?:,$type_re)*\\\]"
+set symtab_re \
+    "\{filename=${qstr},fullname=${qstr},symbols=${sym_list}\}"
+set symtab_type_re \
+    "\{filename=${qstr},fullname=${qstr},symbols=${type_sym_list}\}"
+set debug_only_syms \
+    "symbols=\{debug=\\\[${symtab_re}(?:,${symtab_re})*\\\]\}"
+set all_syms \
+    "symbols=\{debug=\\\[${symtab_re}(?:,${symtab_re})*\\\],nondebug=\\\[.*\\\]\}"
+set type_syms \
+    "symbols=\{debug=\\\[${symtab_type_re}(?:,${symtab_type_re})*\\\]\}"
+
+# Fetch all functions, variables and types without any non-debug
+# symbols.
+mi_gdb_test "111-symbol-info-functions" \
+    "111\\^done,${debug_only_syms}" \
+    "List all functions from debug information only"
+
+mi_gdb_test "112-symbol-info-variables" \
+    "112\\^done,${debug_only_syms}" \
+    "List all variables from debug information only"
+
+mi_gdb_test "113-symbol-info-types" \
+    "113\\^done,${type_syms}" \
+    "List all types"
+
+# Fetch functions and variables but also grab the non-debug symbols
+# (from the symbol table).  There's often so much output output from
+# this command that we overflow expect's buffers, avoid this by
+# fetching the output piece by piece.
+set testname "List all functions"
+gdb_test_multiple "114-symbol-info-functions --include-nondebug" ${testname} {
+    -re "114\\^done,symbols=\{debug=\\\[${symtab_re}(?:,${symtab_re})*\\\],nondebug=\\\[" {
+	exp_continue
+    }
+
+    -re "\{address=${qstr},name=${qstr}\}," {
+	exp_continue
+    }
+
+    -re "\{address=${qstr},name=${qstr}\}\\\]\}\r\n${mi_gdb_prompt}$" {
+	pass ${testname}
+    }
+}
+
+set testname "List all variables"
+gdb_test_multiple "115-symbol-info-variables --include-nondebug" ${testname} {
+    -re "115\\^done,symbols=\{debug=\\\[${symtab_re}(?:,${symtab_re})*\\\],nondebug=\\\[" {
+	verbose -log "Got the first part of the input"
+	exp_continue
+    }
+
+    -re "\{address=${qstr},name=${qstr}\}," {
+	exp_continue
+    }
+
+    -re "\{address=${qstr},name=${qstr}\}\\\]\}\r\n${mi_gdb_prompt}$" {
+	pass ${testname}
+    }
+}
+
+# Filter functions by name and type.
+set lineno [gdb_get_line_number "f3 (another_int_t arg)" ${srcfile2}]
+mi_gdb_test "116-symbol-info-functions --name f3" \
+    "116\\^done,symbols=\{debug=\\\[\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"39\",name=\"f3\",type=\"int \\(another_int_t\\)\",description=\"int f3\\(another_int_t\\);\"\}\\\]\}\\\]\}" \
+    "List all functions matching pattern f3"
+
+set lineno [gdb_get_line_number "f4 (int *arg)" ${srcfile}]
+mi_gdb_test "117-symbol-info-functions --type void" \
+    "117\\^done,symbols=\{debug=\\\[\{filename=\"\[^\"\]+$srcfile\",fullname=\"\[^\"\]+$srcfile\",symbols=\\\[\{line=\"36\",name=\"f4\",type=\"void \\(int \\*\\)\",description=\"void f4\\(int \\*\\);\"\}\\\]\}\\\]\}" \
+    "List all functions matching type void"
+
+# Filter variables by name and type.
+set lineno [gdb_get_line_number "int global_f2;" ${srcfile2}]
+mi_gdb_test "118-symbol-info-variables --name global_f2" \
+    "118\\^done,symbols=\{debug=\\\[\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"21\",name=\"global_f2\",type=\"int\",description=\"int global_f2;\"\}\\\]\}\\\]\}" \
+    "List all variables matching pattern global_f2"
+
+set lineno1 [gdb_get_line_number "static float global_f1;" ${srcfile}]
+set lineno2 [gdb_get_line_number "static float global_f1;" ${srcfile2}]
+mi_gdb_test "119-symbol-info-variables --type float" \
+    "119\\^done,symbols=\{debug=\\\[\{filename=\"\[^\"\]+$srcfile\",fullname=\"\[^\"\]+$srcfile\",symbols=\\\[\{line=\"25\",name=\"global_f1\",type=\"float\",description=\"static float global_f1;\"\}\\\]\},\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"19\",name=\"global_f1\",type=\"float\",description=\"static float global_f1;\"\}\\\]\}\\\]\}" \
+    "List all variables matching type float"
+
+# Fetch types, filtering by name.
+set lineno1 [gdb_get_line_number "typedef int my_int_t;" ${srcfile}]
+set lineno2 [gdb_get_line_number "typedef int another_int_t;" ${srcfile2}]
+mi_gdb_test "120-symbol-info-types --name _int_" \
+    "120\\^done,symbols=\{debug=\\\[\{filename=\"\[^\"\]+$srcfile\",fullname=\"\[^\"\]+$srcfile\",symbols=\\\[\{line=\"27\",name=\"my_int_t\"\}\\\]\},\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"23\",name=\"another_int_t\"\}\\\]\}\\\]\}" \
+    "List all types matching _int_"
-- 
2.14.5

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCHv3 0/9] Fortran 'info module *' commands and MI '-symbol-info-*' commands
@ 2019-10-16 23:28 Andrew Burgess
  2019-10-16 23:28 ` [PATCHv3 4/9] gdb: Introduce symbol_search_spec Andrew Burgess
                   ` (8 more replies)
  0 siblings, 9 replies; 10+ messages in thread
From: Andrew Burgess @ 2019-10-16 23:28 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

This revised series brings together two previously posted series:

(1) https://sourceware.org/ml/gdb-patches/2019-10/msg00101.html

    This series was reviewed, and I've now pushed patches #1 and #2
    from this series.  The previous patches #3 and #4 are the first
    two patches from this series.

    + gdb/fortran: Add new 'info modules' command

      This is pretty much unchanged from the previously posted version
      except for one hunk in 'gdb/dwarf2read.c:scan_partial_symbols'
      where we now only create partial symbols for module
      declarations, and addional tests.  The dwarf2read.c change fixes
      an issue with listing modules from multiple compilation units.

    + gdb: Add new commands to list module variables and functions

      I've fixed Eli's and Tom's feedback from the v2 of this patch.
      I've also split some of the symbol lookup functions in
      gdb/symtab.{c,h}, though the underlying lookup logic is
      unchanged.

(2) https://sourceware.org/ml/gdb-patches/2019-09/msg00543.html

    This series appears as patches #3, #5, and #6 in this new series.

    + gdb: Don't print a newline in language la_print_typedef methods
    
      This patch is unchanged from the original submission.

    + gdb: Split print_symbol_info into two parts

      Basically unchanged, I've addressed Simon's feedback.

    + gdb/mi: Add new commands -symbol-info-{functions,variables,types}

      I've extended the fields that are returned for each symbol,
      splitting out the type and name as requested in the review.  I
      haven't addressed the request to limit the max results in this
      patch, but a later patch in this series adds this feature.
      Otherwise this patch is not massively different.

New Patches

    These are the new patches in this series:

    + gdb: Introduce symbol_search_spec

      I think this makes the symbol_search API a bit cleaner,
      especially as a later patch is going to add yet another search
      parameter.

    + Add -symbol-info-modules command
    + Add -symbol-info-module-{variables,functions}

      New MI commands equivalent to the new CLI commands added
      earlier.

    + gdb/mi: Add -max-results parameter to some -symbol-info-* commands

      Adds the ability to limit the results for some of the
      -symbol-info-* commands as Simon requested in the earlier
      review.

      I DON'T add a limit for -symbol-info-module-variables or
      -symbol-info-module-functions in this commit, the lookup for
      these symbols is more involved, and I can't see an easy way to
      limit the number of results returned without still expanding
      just as many symtabs.  Any suggestions welcome.

Thanks,
Andrew

---

Andrew Burgess (9):
  gdb/fortran: Add new 'info modules' command
  gdb: Add new commands to list module variables and functions
  gdb: Don't print a newline in language la_print_typedef methods
  gdb: Introduce symbol_search_spec
  gdb: Split print_symbol_info into two parts
  gdb/mi: Add new commands -symbol-info-{functions,variables,types}
  gdb/mi: Add -symbol-info-modules command
  gdb/mi: Add -symbol-info-module-{variables,functions}
  gdb/mi: Add -max-results parameter to some -symbol-info-* commands

 gdb/ChangeLog                                 |  124 +++
 gdb/NEWS                                      |   29 +
 gdb/ada-typeprint.c                           |    1 -
 gdb/c-typeprint.c                             |    2 +-
 gdb/doc/ChangeLog                             |   30 +
 gdb/doc/gdb.texinfo                           |  520 ++++++++++++-
 gdb/dwarf2read.c                              |   28 +-
 gdb/f-typeprint.c                             |    1 -
 gdb/m2-typeprint.c                            |    2 +-
 gdb/mi/mi-cmds.c                              |    8 +
 gdb/mi/mi-cmds.h                              |    6 +
 gdb/mi/mi-symbol-cmds.c                       |  413 ++++++++++
 gdb/p-typeprint.c                             |    2 +-
 gdb/psymtab.c                                 |    2 +
 gdb/python/python.c                           |   48 +-
 gdb/rust-lang.c                               |    2 +-
 gdb/symtab.c                                  | 1011 ++++++++++++++++++-------
 gdb/symtab.h                                  |   85 ++-
 gdb/testsuite/ChangeLog                       |   37 +
 gdb/testsuite/gdb.fortran/info-modules.exp    |  187 +++++
 gdb/testsuite/gdb.fortran/info-types-2.f90    |   36 +
 gdb/testsuite/gdb.fortran/info-types.exp      |   11 +-
 gdb/testsuite/gdb.fortran/info-types.f90      |   18 +-
 gdb/testsuite/gdb.mi/mi-fortran-modules-2.f90 |   33 +
 gdb/testsuite/gdb.mi/mi-fortran-modules.exp   |   75 ++
 gdb/testsuite/gdb.mi/mi-fortran-modules.f90   |   87 +++
 gdb/testsuite/gdb.mi/mi-sym-info-1.c          |   48 ++
 gdb/testsuite/gdb.mi/mi-sym-info-2.c          |   43 ++
 gdb/testsuite/gdb.mi/mi-sym-info.exp          |  154 ++++
 29 files changed, 2704 insertions(+), 339 deletions(-)
 create mode 100644 gdb/testsuite/gdb.fortran/info-modules.exp
 create mode 100644 gdb/testsuite/gdb.fortran/info-types-2.f90
 create mode 100644 gdb/testsuite/gdb.mi/mi-fortran-modules-2.f90
 create mode 100644 gdb/testsuite/gdb.mi/mi-fortran-modules.exp
 create mode 100644 gdb/testsuite/gdb.mi/mi-fortran-modules.f90
 create mode 100644 gdb/testsuite/gdb.mi/mi-sym-info-1.c
 create mode 100644 gdb/testsuite/gdb.mi/mi-sym-info-2.c
 create mode 100644 gdb/testsuite/gdb.mi/mi-sym-info.exp

-- 
2.14.5

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCHv3 7/9] gdb/mi: Add -symbol-info-modules command
  2019-10-16 23:28 [PATCHv3 0/9] Fortran 'info module *' commands and MI '-symbol-info-*' commands Andrew Burgess
  2019-10-16 23:28 ` [PATCHv3 4/9] gdb: Introduce symbol_search_spec Andrew Burgess
  2019-10-16 23:28 ` [PATCHv3 6/9] gdb/mi: Add new commands -symbol-info-{functions,variables,types} Andrew Burgess
@ 2019-10-16 23:28 ` Andrew Burgess
  2019-10-16 23:28 ` [PATCHv3 8/9] gdb/mi: Add -symbol-info-module-{variables,functions} Andrew Burgess
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Andrew Burgess @ 2019-10-16 23:28 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

Add '-symbol-info-modules', an MI version of the CLI 'info modules'
command.

gdb/ChangeLog:

	* mi/mi-cmds.c (mi_cmds): Add 'symbol-info-modules' entry.
	* mi/mi-cmds.h (mi_cmd_symbol_info_modules): Declare.
	* mi/mi-symbol-cmds.c (mi_cmd_symbol_info_modules): New function.
	* NEWS: Mention new MI command.

gdb/testsuite/ChangeLog:

	* gdb.mi/mi-fortran-modules-2.f90: New file.
	* gdb.mi/mi-fortran-modules.exp: New file.
	* gdb.mi/mi-fortran-modules.f90: New file.

gdb/doc/ChangeLog:

	* doc/gdb.texinfo (GDB/MI Symbol Query): Document new MI command
	-symbol-info-modules.

Change-Id: Ibc618010d1d5f36ae8a8baba4fb9d9d724e62b0f
---
 gdb/ChangeLog                                 |  7 +++
 gdb/NEWS                                      |  3 +
 gdb/doc/ChangeLog                             |  5 ++
 gdb/doc/gdb.texinfo                           | 54 +++++++++++++++++
 gdb/mi/mi-cmds.c                              |  1 +
 gdb/mi/mi-cmds.h                              |  1 +
 gdb/mi/mi-symbol-cmds.c                       | 37 ++++++++++++
 gdb/testsuite/ChangeLog                       |  6 ++
 gdb/testsuite/gdb.mi/mi-fortran-modules-2.f90 | 33 ++++++++++
 gdb/testsuite/gdb.mi/mi-fortran-modules.exp   | 52 ++++++++++++++++
 gdb/testsuite/gdb.mi/mi-fortran-modules.f90   | 87 +++++++++++++++++++++++++++
 11 files changed, 286 insertions(+)
 create mode 100644 gdb/testsuite/gdb.mi/mi-fortran-modules-2.f90
 create mode 100644 gdb/testsuite/gdb.mi/mi-fortran-modules.exp
 create mode 100644 gdb/testsuite/gdb.mi/mi-fortran-modules.f90

diff --git a/gdb/NEWS b/gdb/NEWS
index 81ad7f26bfb..b8c92e046eb 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -336,6 +336,9 @@ focus, winheight, +, -, >, <
   These commands are the MI equivalent of the CLI commands 'info
   functions', 'info types', and 'info variables' respectively.
 
+-symbol-info-modules, this is the MI equivalent of the CLI 'info
+  modules' command.
+
 * Other MI changes
 
  ** The default version of the MI interpreter is now 3 (-i=mi3).
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 57bcde19894..e8985e107a7 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -33851,6 +33851,60 @@
 @end group
 @end smallexample
 
+@subheading The @code{-symbol-info-modules} Command
+@findex -symbol-info-modules
+@anchor{-symbol-info-modules}
+
+@subsubheading Synopsis
+
+@smallexample
+ -symbol-info-modules [--name @var{name_regexp}]
+@end smallexample
+
+@noindent
+Return a list containing the names of all known Fortran modules.  The
+modules are grouped by source file, and shown with the line number on
+which each modules is defined.
+
+The option @code{--name} allows the modules returned to be filtered
+based the name of the module.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{info modules}.
+
+@subsubheading Example
+@smallexample
+@group
+(gdb)
+-symbol-info-modules
+^done,symbols=
+  @{debug=
+    [@{filename="/project/gdb/testsuite/gdb.mi/mi-fortran-modules-2.f90",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-fortran-modules-2.f90",
+      symbols=[@{line="16",name="mod1"@},
+               @{line="22",name="mod2"@}]@},
+     @{filename="/project/gdb/testsuite/gdb.mi/mi-fortran-modules.f90",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-fortran-modules.f90",
+      symbols=[@{line="16",name="mod3"@},
+               @{line="22",name="modmany"@},
+               @{line="26",name="moduse"@}]@}]@}
+@end group
+@group
+(gdb)
+-symbol-info-modules --name mod[123]
+^done,symbols=
+  @{debug=
+    [@{filename="/project/gdb/testsuite/gdb.mi/mi-fortran-modules-2.f90",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-fortran-modules-2.f90",
+      symbols=[@{line="16",name="mod1"@},
+               @{line="22",name="mod2"@}]@},
+     @{filename="/project/gdb/testsuite/gdb.mi/mi-fortran-modules.f90",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-fortran-modules.f90",
+      symbols=[@{line="16",name="mod3"@}]@}]@}
+@end group
+@end smallexample
+
 @subheading The @code{-symbol-info-types} Command
 @findex -symbol-info-types
 @anchor{-symbol-info-types}
diff --git a/gdb/mi/mi-cmds.c b/gdb/mi/mi-cmds.c
index df9f25fcbd0..85c15ec5357 100644
--- a/gdb/mi/mi-cmds.c
+++ b/gdb/mi/mi-cmds.c
@@ -154,6 +154,7 @@ static struct mi_cmd mi_cmds[] =
   DEF_MI_CMD_MI ("symbol-info-functions", mi_cmd_symbol_info_functions),
   DEF_MI_CMD_MI ("symbol-info-variables", mi_cmd_symbol_info_variables),
   DEF_MI_CMD_MI ("symbol-info-types", mi_cmd_symbol_info_types),
+  DEF_MI_CMD_MI ("symbol-info-modules", mi_cmd_symbol_info_modules),
   DEF_MI_CMD_CLI ("target-attach", "attach", 1),
   DEF_MI_CMD_MI ("target-detach", mi_cmd_target_detach),
   DEF_MI_CMD_CLI ("target-disconnect", "disconnect", 0),
diff --git a/gdb/mi/mi-cmds.h b/gdb/mi/mi-cmds.h
index c2fd7d30d63..30de780286b 100644
--- a/gdb/mi/mi-cmds.h
+++ b/gdb/mi/mi-cmds.h
@@ -95,6 +95,7 @@ extern mi_cmd_argv_ftype mi_cmd_stack_list_variables;
 extern mi_cmd_argv_ftype mi_cmd_stack_select_frame;
 extern mi_cmd_argv_ftype mi_cmd_symbol_list_lines;
 extern mi_cmd_argv_ftype mi_cmd_symbol_info_functions;
+extern mi_cmd_argv_ftype mi_cmd_symbol_info_modules;
 extern mi_cmd_argv_ftype mi_cmd_symbol_info_types;
 extern mi_cmd_argv_ftype mi_cmd_symbol_info_variables;
 extern mi_cmd_argv_ftype mi_cmd_target_detach;
diff --git a/gdb/mi/mi-symbol-cmds.c b/gdb/mi/mi-symbol-cmds.c
index 6b0aa9538f5..ecf5293f874 100644
--- a/gdb/mi/mi-symbol-cmds.c
+++ b/gdb/mi/mi-symbol-cmds.c
@@ -238,6 +238,43 @@ mi_cmd_symbol_info_functions (const char *command, char **argv, int argc)
   mi_info_functions_or_variables (FUNCTIONS_DOMAIN, argv, argc);
 }
 
+/* Implement -symbol-inf-modules command.  */
+
+void
+mi_cmd_symbol_info_modules (const char *command, char **argv, int argc)
+{
+  const char *regexp = nullptr;
+
+  enum opt
+    {
+     NAME_REGEXP_OPT
+    };
+  static const struct mi_opt opts[] =
+  {
+    {"-name", NAME_REGEXP_OPT, 1},
+    { 0, 0, 0 }
+  };
+
+  int oind = 0;
+  char *oarg = nullptr;
+
+  while (1)
+    {
+      int opt = mi_getopt ("-symbol-info-modules", argc, argv, opts,
+			   &oind, &oarg);
+      if (opt < 0)
+	break;
+      switch ((enum opt) opt)
+	{
+	case NAME_REGEXP_OPT:
+	  regexp = oarg;
+	  break;
+	}
+    }
+
+  mi_symbol_info (MODULES_DOMAIN, regexp, nullptr, true);
+}
+
 /* Implement -symbol-info-types command.  */
 
 void
diff --git a/gdb/testsuite/gdb.mi/mi-fortran-modules-2.f90 b/gdb/testsuite/gdb.mi/mi-fortran-modules-2.f90
new file mode 100644
index 00000000000..690d54dde8c
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-fortran-modules-2.f90
@@ -0,0 +1,33 @@
+! Copyright 2009-2019 Free Software Foundation, Inc.
+!
+! This program is free software; you can redistribute it and/or modify
+! it under the terms of the GNU General Public License as published by
+! the Free Software Foundation; either version 3 of the License, or
+! (at your option) any later version.
+!
+! This program is distributed in the hope that it will be useful,
+! but WITHOUT ANY WARRANTY; without even the implied warranty of
+! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+! GNU General Public License for more details.
+!
+! You should have received a copy of the GNU General Public License
+! along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+module mod1
+  integer :: var_i = 1
+  integer :: var_const
+  parameter (var_const = 20)
+contains
+  subroutine check_all
+    if (var_i .ne. 1) call abort
+    if (var_const .ne. 20) call abort
+  end subroutine check_all
+end module mod1
+
+module mod2
+  integer :: var_i = 2
+contains
+    subroutine check_var_i
+    if (var_i .ne. 2) call abort
+  end subroutine check_var_i
+end module mod2
diff --git a/gdb/testsuite/gdb.mi/mi-fortran-modules.exp b/gdb/testsuite/gdb.mi/mi-fortran-modules.exp
new file mode 100644
index 00000000000..640bb12642d
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-fortran-modules.exp
@@ -0,0 +1,52 @@
+# Copyright 2019 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test -symbol-info-modules, listing Fortran modules.
+
+load_lib fortran.exp
+load_lib mi-support.exp
+set MIFLAGS "-i=mi"
+
+standard_testfile "mi-fortran-modules.f90" "mi-fortran-modules-2.f90"
+
+if {[prepare_for_testing "failed to prepare" ${testfile} \
+	 [list $srcfile $srcfile2] {debug f90}]} {
+    return -1
+}
+
+gdb_exit
+if {[mi_gdb_start]} {
+    continue
+}
+
+mi_run_to_main
+
+mi_gdb_test "101-symbol-info-modules" \
+    "101\\^done,symbols=\{debug=\\\[\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"16\",name=\"mod1\"\},\{line=\"27\",name=\"mod2\"\}\\\]\},\{filename=\"\[^\"\]+$srcfile\",fullname=\"\[^\"\]+$srcfile\",symbols=\\\[\{line=\"16\",name=\"mod3\"\},\{line=\"32\",name=\"modmany\"\},\{line=\"41\",name=\"moduse\"\}\\\]\}\\\]\}" \
+    "-symbol-info-modules"
+
+mi_gdb_test "102-symbol-info-modules --name mod\[123\]" \
+    "102\\^done,symbols=\{debug=\\\[\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"16\",name=\"mod1\"\},\{line=\"27\",name=\"mod2\"\}\\\]\},\{filename=\"\[^\"\]+$srcfile\",fullname=\"\[^\"\]+$srcfile\",symbols=\\\[\{line=\"16\",name=\"mod3\"\}\\\]\}\\\]\}" \
+    "-symbol-info-modules --name mod\[123\]"
+
+mi_gdb_test "103-symbol-info-modules --name moduse" \
+    "103\\^done,symbols=\{debug=\\\[\{filename=\"\[^\"\]+$srcfile\",fullname=\"\[^\"\]+$srcfile\",symbols=\\\[\{line=\"41\",name=\"moduse\"\}\\\]\}\\\]\}" \
+    "-symbol-info-modules --name moduse"
+
+
+
+
+
+
diff --git a/gdb/testsuite/gdb.mi/mi-fortran-modules.f90 b/gdb/testsuite/gdb.mi/mi-fortran-modules.f90
new file mode 100644
index 00000000000..d2546270c6e
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-fortran-modules.f90
@@ -0,0 +1,87 @@
+! Copyright 2009-2019 Free Software Foundation, Inc.
+! 
+! This program is free software; you can redistribute it and/or modify
+! it under the terms of the GNU General Public License as published by
+! the Free Software Foundation; either version 3 of the License, or
+! (at your option) any later version.
+! 
+! This program is distributed in the hope that it will be useful,
+! but WITHOUT ANY WARRANTY; without even the implied warranty of
+! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+! GNU General Public License for more details.
+! 
+! You should have received a copy of the GNU General Public License
+! along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+module mod3
+  integer :: mod2 = 3
+  integer :: mod1 = 3
+  integer :: var_i = 3
+contains
+  subroutine check_all
+    if (mod2 .ne. 3) call abort
+    if (mod1 .ne. 3) call abort
+    if (var_i .ne. 3) call abort
+  end subroutine check_all
+
+  subroutine check_mod2
+    if (mod2 .ne. 3) call abort
+  end subroutine check_mod2
+end module mod3
+
+module modmany
+  integer :: var_a = 10, var_b = 11, var_c = 12, var_i = 14
+contains
+  subroutine check_some
+    if (var_a .ne. 10) call abort
+    if (var_b .ne. 11) call abort
+  end subroutine check_some
+end module modmany
+
+module moduse
+  integer :: var_x = 30, var_y = 31
+contains
+  subroutine check_all
+    if (var_x .ne. 30) call abort
+    if (var_y .ne. 31) call abort
+  end subroutine check_all
+
+  subroutine check_var_x
+    if (var_x .ne. 30) call abort
+  end subroutine check_var_x
+end module moduse
+
+subroutine sub1
+  use mod1
+  if (var_i .ne. 1) call abort
+  var_i = var_i                         ! i-is-1
+end subroutine sub1
+
+subroutine sub2
+  use mod2
+  if (var_i .ne. 2) call abort
+  var_i = var_i                         ! i-is-2
+end subroutine sub2
+
+subroutine sub3
+  use mod3
+  var_i = var_i                         ! i-is-3
+end subroutine sub3
+
+program module
+
+  use modmany, only: var_b, var_d => var_c, var_i
+  use moduse, var_z => var_y
+
+  call sub1
+  call sub2
+  call sub3
+
+  if (var_b .ne. 11) call abort
+  if (var_d .ne. 12) call abort
+  if (var_i .ne. 14) call abort
+  if (var_x .ne. 30) call abort
+  if (var_z .ne. 31) call abort
+  var_b = var_b                         ! a-b-c-d
+
+end program module
-- 
2.14.5

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCHv3 8/9] gdb/mi: Add -symbol-info-module-{variables,functions}
  2019-10-16 23:28 [PATCHv3 0/9] Fortran 'info module *' commands and MI '-symbol-info-*' commands Andrew Burgess
                   ` (2 preceding siblings ...)
  2019-10-16 23:28 ` [PATCHv3 7/9] gdb/mi: Add -symbol-info-modules command Andrew Burgess
@ 2019-10-16 23:28 ` Andrew Burgess
  2019-10-16 23:28 ` [PATCHv3 9/9] gdb/mi: Add -max-results parameter to some -symbol-info-* commands Andrew Burgess
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Andrew Burgess @ 2019-10-16 23:28 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

Two new MI command -symbol-info-module-variables and
-symbol-info-module-functions, which are the equivalent of the CLI
command 'info module variables' and 'info module functions'.  These
return information about functions and variables within Fortran
modules.

gdb/ChangeLog:

	* mi/mi-cmds.c (mi_cmds): Add -symbol-info-module-functions and
	-symbol-info-module-variables entries.
	* mi/mi-cmds.h (mi_cmd_symbol_info_module_functions): Declare.
	(mi_cmd_symbol_info_module_variables): Declare.
	* mi/mi-symbol-cmds.c (mi_info_module_functions_or_variables): New
	function.
	(mi_cmd_symbol_info_module_functions): New function.
	(mi_cmd_symbol_info_module_variables): New function.
	* NEWS: Mention new MI command.

gdb/doc/ChangeLog:

	* doc/gdb.texinfo (GDB/MI Symbol Query): Document new MI command
	-symbol-info-module-functions and -symbol-info-module-variables.

gdb/testsuite/ChangeLog:

	* gdb.mi/mi-fortran-modules.exp: Add additional tests for
	-symbol-info-module-functions and -symbol-info-module-variables.

Change-Id: Ic96f12dd14bd7e34774c3cde008fec30a4055bfe
---
 gdb/ChangeLog                               |  12 +++
 gdb/NEWS                                    |   4 +
 gdb/doc/ChangeLog                           |   5 +
 gdb/doc/gdb.texinfo                         | 142 ++++++++++++++++++++++++++++
 gdb/mi/mi-cmds.c                            |   4 +
 gdb/mi/mi-cmds.h                            |   2 +
 gdb/mi/mi-symbol-cmds.c                     | 119 ++++++++++++++++++++++-
 gdb/testsuite/ChangeLog                     |   5 +
 gdb/testsuite/gdb.mi/mi-fortran-modules.exp |  25 ++++-
 9 files changed, 316 insertions(+), 2 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index b8c92e046eb..9072d542f7b 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -339,6 +339,10 @@ focus, winheight, +, -, >, <
 -symbol-info-modules, this is the MI equivalent of the CLI 'info
   modules' command.
 
+-symbol-info-module-functions and -symbol-info-module-variables.
+  These commands are the MI equivalent of the CLI commands 'info
+  module functions' and 'info module variables'.
+
 * Other MI changes
 
  ** The default version of the MI interpreter is now 3 (-i=mi3).
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index e8985e107a7..4404c05e225 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -33851,6 +33851,148 @@
 @end group
 @end smallexample
 
+@subheading The @code{-symbol-info-module-functions} Command
+@findex -symbol-info-module-functions
+@anchor{-symbol-info-module-functions}
+
+@subsubheading Synopsis
+
+@smallexample
+ -symbol-info-module-functions [--module @var{module_regexp}]
+                               [--name @var{name_regexp}]
+                               [--type @var{type_regexp}]
+@end smallexample
+
+@noindent
+Return a list containing the names of all known functions within all
+know Fortran modules.  The functions are grouped by source file and
+containing module, and shown with the line number on which each
+function is defined.
+
+The option @code{--module} only returns results for modules matching
+@var{module_regexp}.  The option @code{--name} only returns functions
+whose name matches @var{name_regexp}, and @code{--type} only returns
+functions whose type matches @var{type_regexp}.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{info module functions}.
+
+@subsubheading Example
+
+@smallexample
+@group
+(gdb)
+-symbol-info-module-functions
+^done,symbols=
+  [@{module="mod1",
+    files=[@{filename="/project/gdb/testsuite/gdb.mi/mi-fortran-modules-2.f90",
+            fullname="/project/gdb/testsuite/gdb.mi/mi-fortran-modules-2.f90",
+            symbols=[@{line="21",name="mod1::check_all",type="void (void)",
+                      description="void mod1::check_all(void);"@}]@}]@},
+    @{module="mod2",
+     files=[@{filename="/project/gdb/testsuite/gdb.mi/mi-fortran-modules-2.f90",
+             fullname="/project/gdb/testsuite/gdb.mi/mi-fortran-modules-2.f90",
+             symbols=[@{line="30",name="mod2::check_var_i",type="void (void)",
+                       description="void mod2::check_var_i(void);"@}]@}]@},
+    @{module="mod3",
+     files=[@{filename="/projec/gdb/testsuite/gdb.mi/mi-fortran-modules.f90",
+             fullname="/projec/gdb/testsuite/gdb.mi/mi-fortran-modules.f90",
+             symbols=[@{line="21",name="mod3::check_all",type="void (void)",
+                       description="void mod3::check_all(void);"@},
+                      @{line="27",name="mod3::check_mod2",type="void (void)",
+                       description="void mod3::check_mod2(void);"@}]@}]@},
+    @{module="modmany",
+     files=[@{filename="/project/gdb/testsuite/gdb.mi/mi-fortran-modules.f90",
+             fullname="/project/gdb/testsuite/gdb.mi/mi-fortran-modules.f90",
+             symbols=[@{line="35",name="modmany::check_some",type="void (void)",
+                       description="void modmany::check_some(void);"@}]@}]@},
+    @{module="moduse",
+     files=[@{filename="/project/gdb/testsuite/gdb.mi/mi-fortran-modules.f90",
+             fullname="/project/gdb/testsuite/gdb.mi/mi-fortran-modules.f90",
+             symbols=[@{line="44",name="moduse::check_all",type="void (void)",
+                       description="void moduse::check_all(void);"@},
+                      @{line="49",name="moduse::check_var_x",type="void (void)",
+                       description="void moduse::check_var_x(void);"@}]@}]@}]
+@end group
+@end smallexample
+
+@subheading The @code{-symbol-info-module-variables} Command
+@findex -symbol-info-module-variables
+@anchor{-symbol-info-module-variables}
+
+@subsubheading Synopsis
+
+@smallexample
+ -symbol-info-module-variables [--module @var{module_regexp}]
+                               [--name @var{name_regexp}]
+                               [--type @var{type_regexp}]
+@end smallexample
+
+@noindent
+Return a list containing the names of all known variables within all
+know Fortran modules.  The variables are grouped by source file and
+containing module, and shown with the line number on which each
+variable is defined.
+
+The option @code{--module} only returns results for modules matching
+@var{module_regexp}.  The option @code{--name} only returns variables
+whose name matches @var{name_regexp}, and @code{--type} only returns
+variables whose type matches @var{type_regexp}.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{info module variables}.
+
+@subsubheading Example
+
+@smallexample
+@group
+(gdb)
+-symbol-info-module-variables
+^done,symbols=
+  [@{module="mod1",
+    files=[@{filename="/project/gdb/testsuite/gdb.mi/mi-fortran-modules-2.f90",
+            fullname="/project/gdb/testsuite/gdb.mi/mi-fortran-modules-2.f90",
+            symbols=[@{line="18",name="mod1::var_const",type="integer(kind=4)",
+                      description="integer(kind=4) mod1::var_const;"@},
+                     @{line="17",name="mod1::var_i",type="integer(kind=4)",
+                      description="integer(kind=4) mod1::var_i;"@}]@}]@},
+   @{module="mod2",
+    files=[@{filename="/project/gdb/testsuite/gdb.mi/mi-fortran-modules-2.f90",
+            fullname="/project/gdb/testsuite/gdb.mi/mi-fortran-modules-2.f90",
+            symbols=[@{line="28",name="mod2::var_i",type="integer(kind=4)",
+                      description="integer(kind=4) mod2::var_i;"@}]@}]@},
+   @{module="mod3",
+    files=[@{filename="/project/gdb/testsuite/gdb.mi/mi-fortran-modules.f90",
+            fullname="/project/gdb/testsuite/gdb.mi/mi-fortran-modules.f90",
+            symbols=[@{line="18",name="mod3::mod1",type="integer(kind=4)",
+                      description="integer(kind=4) mod3::mod1;"@},
+                     @{line="17",name="mod3::mod2",type="integer(kind=4)",
+                      description="integer(kind=4) mod3::mod2;"@},
+                     @{line="19",name="mod3::var_i",type="integer(kind=4)",
+                      description="integer(kind=4) mod3::var_i;"@}]@}]@},
+   @{module="modmany",
+    files=[@{filename="/project/gdb/testsuite/gdb.mi/mi-fortran-modules.f90",
+            fullname="/project/gdb/testsuite/gdb.mi/mi-fortran-modules.f90",
+            symbols=[@{line="33",name="modmany::var_a",type="integer(kind=4)",
+                      description="integer(kind=4) modmany::var_a;"@},
+                     @{line="33",name="modmany::var_b",type="integer(kind=4)",
+                      description="integer(kind=4) modmany::var_b;"@},
+                     @{line="33",name="modmany::var_c",type="integer(kind=4)",
+                      description="integer(kind=4) modmany::var_c;"@},
+                     @{line="33",name="modmany::var_i",type="integer(kind=4)",
+                      description="integer(kind=4) modmany::var_i;"@}]@}]@},
+   @{module="moduse",
+    files=[@{filename="/project/gdb/testsuite/gdb.mi/mi-fortran-modules.f90",
+            fullname="/project/gdb/testsuite/gdb.mi/mi-fortran-modules.f90",
+            symbols=[@{line="42",name="moduse::var_x",type="integer(kind=4)",
+                      description="integer(kind=4) moduse::var_x;"@},
+                     @{line="42",name="moduse::var_y",type="integer(kind=4)",
+                      description="integer(kind=4) moduse::var_y;"@}]@}]@}]
+@end group
+@end smallexample
+
 @subheading The @code{-symbol-info-modules} Command
 @findex -symbol-info-modules
 @anchor{-symbol-info-modules}
diff --git a/gdb/mi/mi-cmds.c b/gdb/mi/mi-cmds.c
index 85c15ec5357..991fb4b9c20 100644
--- a/gdb/mi/mi-cmds.c
+++ b/gdb/mi/mi-cmds.c
@@ -155,6 +155,10 @@ static struct mi_cmd mi_cmds[] =
   DEF_MI_CMD_MI ("symbol-info-variables", mi_cmd_symbol_info_variables),
   DEF_MI_CMD_MI ("symbol-info-types", mi_cmd_symbol_info_types),
   DEF_MI_CMD_MI ("symbol-info-modules", mi_cmd_symbol_info_modules),
+  DEF_MI_CMD_MI ("symbol-info-module-functions",
+		 mi_cmd_symbol_info_module_functions),
+  DEF_MI_CMD_MI ("symbol-info-module-variables",
+		 mi_cmd_symbol_info_module_variables),
   DEF_MI_CMD_CLI ("target-attach", "attach", 1),
   DEF_MI_CMD_MI ("target-detach", mi_cmd_target_detach),
   DEF_MI_CMD_CLI ("target-disconnect", "disconnect", 0),
diff --git a/gdb/mi/mi-cmds.h b/gdb/mi/mi-cmds.h
index 30de780286b..faeb36b40ee 100644
--- a/gdb/mi/mi-cmds.h
+++ b/gdb/mi/mi-cmds.h
@@ -95,6 +95,8 @@ extern mi_cmd_argv_ftype mi_cmd_stack_list_variables;
 extern mi_cmd_argv_ftype mi_cmd_stack_select_frame;
 extern mi_cmd_argv_ftype mi_cmd_symbol_list_lines;
 extern mi_cmd_argv_ftype mi_cmd_symbol_info_functions;
+extern mi_cmd_argv_ftype mi_cmd_symbol_info_module_functions;
+extern mi_cmd_argv_ftype mi_cmd_symbol_info_module_variables;
 extern mi_cmd_argv_ftype mi_cmd_symbol_info_modules;
 extern mi_cmd_argv_ftype mi_cmd_symbol_info_types;
 extern mi_cmd_argv_ftype mi_cmd_symbol_info_variables;
diff --git a/gdb/mi/mi-symbol-cmds.c b/gdb/mi/mi-symbol-cmds.c
index ecf5293f874..64f24f6bae5 100644
--- a/gdb/mi/mi-symbol-cmds.c
+++ b/gdb/mi/mi-symbol-cmds.c
@@ -230,6 +230,106 @@ mi_info_functions_or_variables (enum search_domain kind, char **argv, int argc)
   mi_symbol_info (kind, regexp, t_regexp, exclude_minsyms);
 }
 
+/* Core of -symbol-info-module-functions and -symbol-info-module-variables.
+   KIND indicates what we are searching for, and ARGV and ARGC are the
+   command line options passed to the MI command.  */
+
+static void
+mi_info_module_functions_or_variables (enum search_domain kind,
+					char **argv, int argc)
+{
+  const char *module_regexp = nullptr;
+  const char *regexp = nullptr;
+  const char *type_regexp = nullptr;
+
+  /* Process the command line options.  */
+
+  enum opt
+    {
+     MODULE_REGEXP_OPT, TYPE_REGEXP_OPT, NAME_REGEXP_OPT
+    };
+  static const struct mi_opt opts[] =
+  {
+    {"-module", MODULE_REGEXP_OPT, 1},
+    {"-type", TYPE_REGEXP_OPT, 1},
+    {"-name", NAME_REGEXP_OPT, 1},
+    { 0, 0, 0 }
+  };
+
+  int oind = 0;
+  char *oarg = nullptr;
+
+  while (1)
+    {
+      const char *cmd_string
+	= ((kind == FUNCTIONS_DOMAIN)
+	   ? "-symbol-info-module-functions"
+	   : "-symbol-info-module-variables");
+      int opt = mi_getopt (cmd_string, argc, argv, opts, &oind, &oarg);
+      if (opt < 0)
+	break;
+      switch ((enum opt) opt)
+	{
+	case MODULE_REGEXP_OPT:
+	  module_regexp = oarg;
+	  break;
+	case TYPE_REGEXP_OPT:
+	  type_regexp = oarg;
+	  break;
+	case NAME_REGEXP_OPT:
+	  regexp = oarg;
+	  break;
+	}
+    }
+
+  std::vector<module_symbol_search> module_symbols
+    = search_module_symbols (module_regexp, regexp, type_regexp, kind);
+
+  struct ui_out *uiout = current_uiout;
+  ui_out_emit_list all_matching_symbols (uiout, "symbols");
+  gdb::optional<ui_out_emit_tuple> module_tuple;
+  gdb::optional<ui_out_emit_list> files_list;
+  gdb::optional<ui_out_emit_tuple> current_file;
+  gdb::optional<ui_out_emit_list> item_list;
+
+  const symtab *last_symtab = nullptr;
+  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)
+	{
+	  item_list.reset ();
+	  current_file.reset ();
+	  files_list.reset ();
+
+	  module_tuple.emplace (uiout, nullptr);
+	  uiout->field_string ("module", SYMBOL_PRINT_NAME (p.symbol));
+	  last_module_symbol = p.symbol;
+	  last_symtab = nullptr;
+	  files_list.emplace (uiout, "files");
+	}
+
+      struct symtab *s = symbol_symtab (q.symbol);
+      if (last_symtab != s)
+	{
+	  item_list.reset ();
+	  current_file.emplace (uiout, nullptr);
+	  uiout->field_string ("filename",
+			       symtab_to_filename_for_display (s));
+	  uiout->field_string ("fullname", symtab_to_fullname (s));
+	  item_list.emplace (uiout, "symbols");
+	  last_symtab = s;
+	}
+
+      mi_info_one_symbol_details (kind, q.symbol, q.block);
+    }
+}
+
 /* Implement -symbol-info-functions command.  */
 
 void
@@ -238,6 +338,24 @@ mi_cmd_symbol_info_functions (const char *command, char **argv, int argc)
   mi_info_functions_or_variables (FUNCTIONS_DOMAIN, argv, argc);
 }
 
+/* Implement -symbol-info-module-functions command.  */
+
+void
+mi_cmd_symbol_info_module_functions (const char *command, char **argv,
+				     int argc)
+{
+  mi_info_module_functions_or_variables (FUNCTIONS_DOMAIN, argv, argc);
+}
+
+/* Implement -symbol-info-module-variables command.  */
+
+void
+mi_cmd_symbol_info_module_variables (const char *command, char **argv,
+				     int argc)
+{
+  mi_info_module_functions_or_variables (VARIABLES_DOMAIN, argv, argc);
+}
+
 /* Implement -symbol-inf-modules command.  */
 
 void
@@ -319,4 +437,3 @@ mi_cmd_symbol_info_variables (const char *command, char **argv, int argc)
 {
   mi_info_functions_or_variables (VARIABLES_DOMAIN, argv, argc);
 }
-
diff --git a/gdb/testsuite/gdb.mi/mi-fortran-modules.exp b/gdb/testsuite/gdb.mi/mi-fortran-modules.exp
index 640bb12642d..12a81a68695 100644
--- a/gdb/testsuite/gdb.mi/mi-fortran-modules.exp
+++ b/gdb/testsuite/gdb.mi/mi-fortran-modules.exp
@@ -45,7 +45,30 @@ mi_gdb_test "103-symbol-info-modules --name moduse" \
     "103\\^done,symbols=\{debug=\\\[\{filename=\"\[^\"\]+$srcfile\",fullname=\"\[^\"\]+$srcfile\",symbols=\\\[\{line=\"41\",name=\"moduse\"\}\\\]\}\\\]\}" \
     "-symbol-info-modules --name moduse"
 
-
+mi_gdb_test "104-symbol-info-module-functions" \
+    [join \
+     [list \
+      "104\\^done,symbols=\\\[\{module=\"mod1\",files=\\\[\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"21\",name=\"mod1::check_all\",type=\"void \\(void\\)\",description=\"void mod1::check_all\\(void\\);\"\}\\\]\}\\\]\},\{module=\"mod2\",files=\\\[\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"30\",name=\"mod2::check_var_i\",type=\"void \\(void\\)\",description=\"void mod2::check_var_i\\(void\\);\"\}\\\]\}\\\]\},\{module=\"mod3\",files=\\\[\{filename=\"\[^\"\]+$srcfile\",fullname=\"\[^\"\]+$srcfile\",symbols=\\\[\{line=\"21\",name=\"mod3::check_all\",type=\"void \\(void\\)\",description=\"void mod3::check_all\\(void\\);\"\},\{line=\"27\",name=\"mod3::check_mod2\",type=\"void \\(void\\)\",description=\"void mod3::check_mod2\\(void\\);\"\}\\\]\}\\\]\}," \
+	  "\{module=\"modmany\",files=\\\[\{filename=\"\[^\"\]+$srcfile\",fullname=\"\[^\"\]+$srcfile\",symbols=\\\[\{line=\"35\",name=\"modmany::check_some\",type=\"void \\(void\\)\",description=\"void modmany::check_some\\(void\\);\"\}\\\]\}\\\]\},\{module=\"moduse\",files=\\\[\{filename=\"\[^\"\]+$srcfile\",fullname=\"\[^\"\]+$srcfile\",symbols=\\\[\{line=\"44\",name=\"moduse::check_all\",type=\"void \\(void\\)\",description=\"void moduse::check_all\\(void\\);\"\},\{line=\"49\",name=\"moduse::check_var_x\",type=\"void \\(void\\)\",description=\"void moduse::check_var_x\\(void\\);\"\}\\\]\}\\\]\}\\\]" ] "" ] \
+    "-symbol-info-module-functions"
+
+mi_gdb_test "105-symbol-info-module-functions --name _all" \
+    "105\\^done,symbols=\\\[\{module=\"mod1\",files=\\\[\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"21\",name=\"mod1::check_all\",type=\"void \\(void\\)\",description=\"void mod1::check_all\\(void\\);\"\}\\\]\}\\\]\},\{module=\"mod3\",files=\\\[\{filename=\"\[^\"\]+$srcfile\",fullname=\"\[^\"\]+$srcfile\",symbols=\\\[\{line=\"21\",name=\"mod3::check_all\",type=\"void \\(void\\)\",description=\"void mod3::check_all\\(void\\);\"\}\\\]\}\\\]\},\{module=\"moduse\",files=\\\[\{filename=\"\[^\"\]+$srcfile\",fullname=\"\[^\"\]+$srcfile\",symbols=\\\[\{line=\"44\",name=\"moduse::check_all\",type=\"void \\(void\\)\",description=\"void moduse::check_all\\(void\\);\"\}\\\]\}\\\]\}\\\]" \
+    "-symbol-info-module-functions --name _all"
+
+mi_gdb_test "106-symbol-info-module-functions --module mod\[123\]" \
+    "106\\^done,symbols=\\\[\{module=\"mod1\",files=\\\[\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"21\",name=\"mod1::check_all\",type=\"void \\(void\\)\",description=\"void mod1::check_all\\(void\\);\"\}\\\]\}\\\]\},\{module=\"mod2\",files=\\\[\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"30\",name=\"mod2::check_var_i\",type=\"void \\(void\\)\",description=\"void mod2::check_var_i\\(void\\);\"\}\\\]\}\\\]\},\{module=\"mod3\",files=\\\[\{filename=\"\[^\"\]+$srcfile\",fullname=\"\[^\"\]+$srcfile\",symbols=\\\[\{line=\"21\",name=\"mod3::check_all\",type=\"void \\(void\\)\",description=\"void mod3::check_all\\(void\\);\"\},\{line=\"27\",name=\"mod3::check_mod2\",type=\"void \\(void\\)\",description=\"void mod3::check_mod2\\(void\\);\"\}\\\]\}\\\]\}\\\]" \
+    "-symbol-info-module-functions --module mod\[123\]"
+
+set int4 [fortran_int4]
+
+mi_gdb_test "107-symbol-info-module-variables" \
+    [join \
+     [list \
+      "107\\^done,symbols=\\\[\{module=\"mod1\",files=\\\[\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"18\",name=\"mod1::var_const\",type=\"$int4\",description=\"$int4 mod1::var_const;\"\},\{line=\"17\",name=\"mod1::var_i\",type=\"$int4\",description=\"$int4 mod1::var_i;\"\}\\\]\}\\\]\},\{module=\"mod2\",files=\\\[\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"28\",name=\"mod2::var_i\",type=\"$int4\",description=\"$int4 mod2::var_i;\"\}\\\]\}\\\]\}," \
+	  "\{module=\"mod3\",files=\\\[\{filename=\"\[^\"\]+$srcfile\",fullname=\"\[^\"\]+$srcfile\",symbols=\\\[\{line=\"18\",name=\"mod3::mod1\",type=\"$int4\",description=\"$int4 mod3::mod1;\"\},\{line=\"17\",name=\"mod3::mod2\",type=\"$int4\",description=\"$int4 mod3::mod2;\"\},\{line=\"19\",name=\"mod3::var_i\",type=\"$int4\",description=\"$int4 mod3::var_i;\"\}\\\]\}\\\]\},\{module=\"modmany\",files=\\\[\{filename=\"\[^\"\]+$srcfile\",fullname=\"\[^\"\]+$srcfile\",symbols=\\\[\{line=\"33\",name=\"modmany::var_a\",type=\"$int4\",description=\"$int4 modmany::var_a;\"\}," \
+	  "\{line=\"33\",name=\"modmany::var_b\",type=\"$int4\",description=\"$int4 modmany::var_b;\"\},\{line=\"33\",name=\"modmany::var_c\",type=\"$int4\",description=\"$int4 modmany::var_c;\"\},\{line=\"33\",name=\"modmany::var_i\",type=\"$int4\",description=\"$int4 modmany::var_i;\"\}\\\]\}\\\]\},\{module=\"moduse\",files=\\\[\{filename=\"\[^\"\]+$srcfile\",fullname=\"\[^\"\]+$srcfile\",symbols=\\\[\{line=\"42\",name=\"moduse::var_x\",type=\"$int4\",description=\"$int4 moduse::var_x;\"\},\{line=\"42\",name=\"moduse::var_y\",type=\"$int4\",description=\"$int4 moduse::var_y;\"\}\\\]\}\\\]\}\\\]" ] "" ] \
+    "-symbol-info-module-variables"
 
 
 
-- 
2.14.5

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCHv3 1/9] gdb/fortran: Add new 'info modules' command
  2019-10-16 23:28 [PATCHv3 0/9] Fortran 'info module *' commands and MI '-symbol-info-*' commands Andrew Burgess
                   ` (6 preceding siblings ...)
  2019-10-16 23:28 ` [PATCHv3 3/9] gdb: Don't print a newline in language la_print_typedef methods Andrew Burgess
@ 2019-10-16 23:28 ` Andrew Burgess
  2019-10-16 23:28 ` [PATCHv3 5/9] gdb: Split print_symbol_info into two parts Andrew Burgess
  8 siblings, 0 replies; 10+ messages in thread
From: Andrew Burgess @ 2019-10-16 23:28 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

Add a new command 'info modules' that lists all of the modules GDB
knows about from the debug information.

A module is a debugging entity in the DWARF defined with
DW_TAG_module, currently Fortran is known to use this tag for its
modules.  I'm not aware of any other language that currently makes use
of DW_TAG_module.

The output style is similar to the 'info type' output:

    (gdb) info modules
    All defined modules:

    File info-types.f90:
    16:     mod1
    24:     mod2
    (gdb)

Where the user is told the file the module is defined in and, on the
left hand side, the line number at which the module is defined along
with the name of the module.

This patch is a new implementation of an idea originally worked on by
Mark O'Connor, Chris January, David Lecomber, and Xavier Oro from ARM.

gdb/ChangeLog:

	* dwarf2read.c (dw2_symtab_iter_next): Handle MODULE_DOMAIN.
	(dw2_expand_marked_cus): Handle MODULES_DOMAIN.
	(dw2_debug_names_iterator::next): Handle MODULE_DOMAIN and
	MODULES_DOMAIN.
	(scan_partial_symbols): Only create partial module symbols for non
	declarations.
	* psymtab.c (recursively_search_psymtabs): Handle MODULE_DOMAIN
	and MODULES_DOMAIN.
	* symtab.c (search_domain_name): Likewise.
	(search_symbols): Likewise.
	(print_symbol_info): Likewise.
	(symtab_symbol_info): Likewise.
	(info_modules_command): New function.
	(_initialize_symtab): Register 'info modules' command.
	* symtab.h (enum search_domain): Add MODULES_DOMAIN.
	* NEWS: Mention new 'info modules' command.

gdb/doc/ChangeLog:

	* gdb.texinfo (Symbols): Document new 'info modules' command.

gdb/testsuite/ChangeLog:

	* gdb.fortran/info-modules.exp: New file.
	* gdb.fortran/info-types.exp: Build with new file.
	* gdb.fortran/info-types.f90: Include and use new module.
	* gdb.fortran/info-types-2.f90: New file.

Change-Id: I2b781dd5a06bcad04620ccdc45f01a0f711adfad
---
 gdb/ChangeLog                              | 19 +++++++++
 gdb/NEWS                                   |  4 ++
 gdb/doc/ChangeLog                          |  4 ++
 gdb/doc/gdb.texinfo                        | 10 +++++
 gdb/dwarf2read.c                           | 28 ++++++++++++-
 gdb/psymtab.c                              |  2 +
 gdb/symtab.c                               | 37 +++++++++++++++--
 gdb/symtab.h                               |  5 ++-
 gdb/testsuite/ChangeLog                    |  7 ++++
 gdb/testsuite/gdb.fortran/info-modules.exp | 66 ++++++++++++++++++++++++++++++
 gdb/testsuite/gdb.fortran/info-types-2.f90 | 20 +++++++++
 gdb/testsuite/gdb.fortran/info-types.exp   |  5 ++-
 gdb/testsuite/gdb.fortran/info-types.f90   |  3 +-
 13 files changed, 201 insertions(+), 9 deletions(-)
 create mode 100644 gdb/testsuite/gdb.fortran/info-modules.exp
 create mode 100644 gdb/testsuite/gdb.fortran/info-types-2.f90

diff --git a/gdb/NEWS b/gdb/NEWS
index 25e67e43c88..e721f3bde44 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -147,6 +147,10 @@ show print frame-info
   'frame', 'stepi'.  The python frame filtering also respect this setting.
   The 'backtrace' '-frame-info' option can override this global setting.
 
+info modules [-q] [REGEXP]
+  Return a list of Fortran modules matching REGEXP, or all modules if
+  no REGEXP is given.
+
 * Changed commands
 
 help
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 1208e4f615e..3f97707c4c1 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -18784,6 +18784,16 @@
 is printed only if its name matches @var{regexp} and its type matches
 @var{type_regexp}.
 
+@kindex info modules
+@cindex modules
+@item info modules [-q] [@var{regexp}]
+List all Fortran modules in the program, or all modules matching the
+optional regular expression @var{regexp}.
+
+The optional flag @samp{-q}, which stands for @samp{quiet}, disables
+printing header information and messages explaining why no modules
+have been printed.
+
 @kindex info classes
 @cindex Objective-C, classes and selectors
 @item info classes
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index a78f818e0e8..b6225845935 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -4021,6 +4021,10 @@ dw2_symtab_iter_next (struct dw2_symtab_iterator *iter)
 	      if (symbol_kind != GDB_INDEX_SYMBOL_KIND_OTHER)
 		continue;
 	      break;
+	    case MODULE_DOMAIN:
+	      if (symbol_kind != GDB_INDEX_SYMBOL_KIND_OTHER)
+		continue;
+	      break;
 	    default:
 	      break;
 	    }
@@ -5043,6 +5047,10 @@ dw2_expand_marked_cus
 	      if (symbol_kind != GDB_INDEX_SYMBOL_KIND_TYPE)
 		continue;
 	      break;
+	    case MODULES_DOMAIN:
+	      if (symbol_kind != GDB_INDEX_SYMBOL_KIND_OTHER)
+		continue;
+	      break;
 	    default:
 	      break;
 	    }
@@ -5949,6 +5957,15 @@ dw2_debug_names_iterator::next ()
 	  goto again;
 	}
       break;
+    case MODULE_DOMAIN:
+      switch (indexval.dwarf_tag)
+	{
+	case DW_TAG_module:
+	  break;
+	default:
+	  goto again;
+	}
+      break;
     default:
       break;
     }
@@ -5985,6 +6002,14 @@ dw2_debug_names_iterator::next ()
 	  goto again;
 	}
       break;
+    case MODULES_DOMAIN:
+      switch (indexval.dwarf_tag)
+	{
+	case DW_TAG_module:
+	  break;
+	default:
+	  goto again;
+	}
     default:
       break;
     }
@@ -8712,7 +8737,8 @@ scan_partial_symbols (struct partial_die_info *first_die, CORE_ADDR *lowpc,
 	      add_partial_namespace (pdi, lowpc, highpc, set_addrmap, cu);
 	      break;
 	    case DW_TAG_module:
-	      add_partial_module (pdi, lowpc, highpc, set_addrmap, cu);
+	      if (!pdi->is_declaration)
+		add_partial_module (pdi, lowpc, highpc, set_addrmap, cu);
 	      break;
 	    case DW_TAG_imported_unit:
 	      {
diff --git a/gdb/psymtab.c b/gdb/psymtab.c
index 31b6d597773..44af8031fc4 100644
--- a/gdb/psymtab.c
+++ b/gdb/psymtab.c
@@ -1272,6 +1272,8 @@ recursively_search_psymtabs
 	  QUIT;
 
 	  if ((domain == ALL_DOMAIN
+	       || (domain == MODULES_DOMAIN
+		   && (*psym)->domain == MODULE_DOMAIN)
 	       || (domain == VARIABLES_DOMAIN
 		   && (*psym)->aclass != LOC_TYPEDEF
 		   && (*psym)->aclass != LOC_BLOCK)
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 8a551f1575a..f41ea3290df 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -297,6 +297,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");
     }
@@ -4474,7 +4475,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 <= MODULES_DOMAIN);
 
   ourtype = types[kind];
   ourtype2 = types2[kind];
@@ -4648,7 +4649,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);
@@ -4779,6 +4783,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
@@ -4819,11 +4828,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 <= MODULES_DOMAIN);
 
   if (regexp != nullptr && *regexp == '\0')
     regexp = nullptr;
@@ -5042,6 +5051,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
@@ -6365,6 +6390,10 @@ 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_com ("rbreak", class_breakpoint, rbreak_command,
 	   _("Set a breakpoint for all functions matching REGEXP."));
 
diff --git a/gdb/symtab.h b/gdb/symtab.h
index dc65409dd24..ba8df9191ff 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -829,8 +829,11 @@ enum search_domain
   /* All defined types */
   TYPES_DOMAIN = 2,
 
+  /* All modules.  */
+  MODULES_DOMAIN = 3,
+
   /* Any type.  */
-  ALL_DOMAIN = 3
+  ALL_DOMAIN = 4
 };
 
 extern const char *search_domain_name (enum search_domain);
diff --git a/gdb/testsuite/gdb.fortran/info-modules.exp b/gdb/testsuite/gdb.fortran/info-modules.exp
new file mode 100644
index 00000000000..f961d28b000
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/info-modules.exp
@@ -0,0 +1,66 @@
+# Copyright 2019 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# This file tests 'info modules'.
+
+load_lib "fortran.exp"
+
+if { [skip_fortran_tests] } { continue }
+
+standard_testfile info-types.f90 info-types-2.f90
+
+if { [prepare_for_testing "failed to prepare" $testfile \
+	  [list $srcfile $srcfile2] {debug f90}] } {
+    return -1
+}
+
+if { ![runto MAIN__] } {
+    perror "Could not run to breakpoint `MAIN__'."
+    continue
+}
+
+gdb_test "info modules" \
+    [multi_line \
+	 "All defined modules:" \
+	 "" \
+	 "File .*${srcfile2}:" \
+	 "18:\[\t \]+mod2" \
+	 "" \
+	 "File .*${srcfile}:" \
+	 "16:\[\t \]+mod1" ]
+
+gdb_test "info modules 1" \
+    [multi_line \
+	 "All modules matching regular expression \"1\":" \
+	 "" \
+	 "File .*${srcfile}:" \
+	 "16:\[\t \]+mod1" ]
+
+gdb_test "info modules 2" \
+    [multi_line \
+	 "All modules matching regular expression \"2\":" \
+	 "" \
+	 "File .*${srcfile2}:" \
+	 "18:\[\t \]+mod2" ]
+
+gdb_test "info modules mod" \
+    [multi_line \
+	 "All modules matching regular expression \"mod\":" \
+	 "" \
+	 "File .*${srcfile2}:" \
+	 "18:\[\t \]+mod2" \
+	 "" \
+	 "File .*${srcfile}:" \
+	 "16:\[\t \]+mod1" ]
diff --git a/gdb/testsuite/gdb.fortran/info-types-2.f90 b/gdb/testsuite/gdb.fortran/info-types-2.f90
new file mode 100644
index 00000000000..a4044184233
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/info-types-2.f90
@@ -0,0 +1,20 @@
+! Copyright 2019 Free Software Foundation, Inc.
+!
+! This program is free software; you can redistribute it and/or modify
+! it under the terms of the GNU General Public License as published by
+! the Free Software Foundation; either version 2 of the License, or
+! (at your option) any later version.
+!
+! This program is distributed in the hope that it will be useful,
+! but WITHOUT ANY WARRANTY; without even the implied warranty of
+! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+! GNU General Public License for more details.
+!
+! You should have received a copy of the GNU General Public License
+! along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+! Comment just to change the line number on which
+! mod2 is defined.
+module mod2
+  integer :: mod2_var_1 = 123
+end module mod2
diff --git a/gdb/testsuite/gdb.fortran/info-types.exp b/gdb/testsuite/gdb.fortran/info-types.exp
index 30646287ee9..1707de88bda 100644
--- a/gdb/testsuite/gdb.fortran/info-types.exp
+++ b/gdb/testsuite/gdb.fortran/info-types.exp
@@ -19,9 +19,10 @@ load_lib "fortran.exp"
 
 if { [skip_fortran_tests] } { continue }
 
-standard_testfile .f90
+standard_testfile info-types.f90 info-types-2.f90
 
-if { [prepare_for_testing "failed to prepare" $testfile $srcfile {debug f90}] } {
+if { [prepare_for_testing "failed to prepare" $testfile \
+	  [list $srcfile $srcfile2] {debug f90}] } {
     return -1
 }
 
diff --git a/gdb/testsuite/gdb.fortran/info-types.f90 b/gdb/testsuite/gdb.fortran/info-types.f90
index 0e27e1ddf08..ec52ef98efc 100644
--- a/gdb/testsuite/gdb.fortran/info-types.f90
+++ b/gdb/testsuite/gdb.fortran/info-types.f90
@@ -21,6 +21,7 @@ end module mod1
 
 program info_types_test
   use mod1
+  use mod2
 
   type :: s1
      integer :: a
@@ -30,7 +31,7 @@ program info_types_test
   type (s1) :: var_a
   type (m1t1) :: var_b
 
-  var_a%a = 1
+  var_a%a = 1 + mod2_var_1
   var_b%b = 2
   l = .FALSE.
 end program info_types_test
-- 
2.14.5

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCHv3 5/9] gdb: Split print_symbol_info into two parts
  2019-10-16 23:28 [PATCHv3 0/9] Fortran 'info module *' commands and MI '-symbol-info-*' commands Andrew Burgess
                   ` (7 preceding siblings ...)
  2019-10-16 23:28 ` [PATCHv3 1/9] gdb/fortran: Add new 'info modules' command Andrew Burgess
@ 2019-10-16 23:28 ` Andrew Burgess
  8 siblings, 0 replies; 10+ messages in thread
From: Andrew Burgess @ 2019-10-16 23:28 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

Split the function print_symbol_info into two parts, the new worker
core returns a string, which print_symbol_info then prints.  This will
be useful in a later commit when some new MI commands will be added
which will use the worker core to fill some MI output fields.

There should be no user visible changes after this commit.

gdb/ChangeLog:

	* symtab.c (symbol_to_info_string): New function, most content
	moved from print_symbol_info, but updated to return a std::string.
	(print_symbol_info): Update to use symbol_to_info_string and print
	returned string.
	* symtab.h (symbol_to_info_string): Declare new function.

Change-Id: I6454ce43cacb61d32fbadb9e3655e70823085777
---
 gdb/ChangeLog |  8 ++++++
 gdb/symtab.c  | 92 ++++++++++++++++++++++++++++++++++++-----------------------
 gdb/symtab.h  |  8 ++++++
 3 files changed, 73 insertions(+), 35 deletions(-)

diff --git a/gdb/symtab.c b/gdb/symtab.c
index b7b65b98ac8..f7affd418cd 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4707,44 +4707,25 @@ search_symbols (const search_symbols_spec &search_spec)
   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
@@ -4754,28 +4735,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);
+		  &tmp_stream, 0);
 
-      printf_filtered (";\n");
+      str += tmp_stream.string ();
+      str += ";";
     }
+  else if (kind == MODULES_DOMAIN)
+    str += SYMBOL_PRINT_NAME (sym);
+
+  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");
+    }
+
   /* 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));
+  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
diff --git a/gdb/symtab.h b/gdb/symtab.h
index f1c7db22505..8852b50a170 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -2126,6 +2126,14 @@ extern std::vector<module_symbol_search> search_module_symbols
 	(const char *module_regexp, const char *regexp,
 	 const char *type_regexp, search_domain kind);
 
+/* Convert a global or static symbol SYM (based on BLOCK, which should be
+   either GLOBAL_BLOCK or STATIC_BLOCK) into a string for use in 'info'
+   type commands (e.g. 'info variables', 'info functions', etc).  KIND is
+   the type of symbol that was searched for which gave us SYM.  */
+
+extern std::string symbol_to_info_string (struct symbol *sym, int block,
+					  enum search_domain kind);
+
 extern bool treg_matches_sym_type_name (const compiled_regex &treg,
 					const struct symbol *sym);
 
-- 
2.14.5

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCHv3 2/9] gdb: Add new commands to list module variables and functions
  2019-10-16 23:28 [PATCHv3 0/9] Fortran 'info module *' commands and MI '-symbol-info-*' commands Andrew Burgess
                   ` (4 preceding siblings ...)
  2019-10-16 23:28 ` [PATCHv3 9/9] gdb/mi: Add -max-results parameter to some -symbol-info-* commands Andrew Burgess
@ 2019-10-16 23:28 ` Andrew Burgess
  2019-10-16 23:28 ` [PATCHv3 3/9] gdb: Don't print a newline in language la_print_typedef methods Andrew Burgess
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Andrew Burgess @ 2019-10-16 23:28 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

This patch adds two new commands "info module functions" and "info
module variables".  These commands list all of the functions and
variables grouped by module and then by file.

For example:

  (gdb) info module functions
  All functions in all modules:

  Module "mod1":

  File /some/path/gdb/testsuite/gdb.fortran/info-types.f90:
  35:	void mod1::__copy_mod1_M1t1(Type m1t1, Type m1t1);
  25:	void mod1::sub_m1_a(integer(kind=4));
  31:	integer(kind=4) mod1::sub_m1_b(void);

  Module "mod2":

  File /some/path/gdb/testsuite/gdb.fortran/info-types.f90:
  41:	void mod2::sub_m2_a(integer(kind=4), logical(kind=4));
  49:	logical(kind=4) mod2::sub_m2_b(real(kind=4));

The new commands take set of flags that allow the output to be
filtered, the user can filter by variable/function name, type, or
containing module.

As GDB doesn't currently track the relationship between a module and
the variables or functions within it in the symbol table, so I filter
based on the module prefix in order to find the functions or variables
in each module.  What this makes clear is that a user could get this
same information using "info variables" and simply provide the prefix
themselves, for example:

  (gdb) info module functions -m mod1 _a
  All functions matching regular expression "_a",
  	in all modules matching regular expression "mod1":

  Module "mod1":

  File /some/path/gdb/testsuite/gdb.fortran/info-types.f90:
  25:	void mod1::sub_m1_a(integer(kind=4));

Is similar to:

  (gdb) info functions mod1::.*_a.*
  All functions matching regular expression "mod1::.*_a":

  File /some/path/gdb/testsuite/gdb.fortran/info-types.f90:
  25:	void mod1::sub_m1_a(integer(kind=4));

The benefits I see for a separate command are that the user doesn't
have to think (or know) about the module prefix format, nor worry
about building a proper regexp.  The user can also easily can across
modules without having to build complex regexps.

The new function search_module_symbols is extern in this patch despite
only being used within symtab.c, this is because a later patch in this
series will also be using this function from outside symtab.c.

This patch is a new implementation of an idea originally worked on by
Mark O'Connor, Chris January, David Lecomber, and Xavier Oro from ARM.

gdb/ChangeLog:

	* symtab.c (info_module_cmdlist): New variable.
	(info_module_command): New function.
	(search_module_symbols): New function.
	(info_module_subcommand): New function.
	(struct info_modules_var_func_options): New struct.
	(info_modules_var_func_options_defs): New variable.
	(make_info_modules_var_func_options_def_group): New function.
	(info_module_functions_command): New function.
	(info_module_variables_command): New function.
	(info_module_var_func_command_completer): New function.
	(_initialize_symtab): Register new 'info module functions' and
	'info module variables' commands.
	* symtab.h (typedef symbol_search_in_module): New typedef.
	(search_module_symbols): Declare new function.
	* NEWS: Mention new commands.

gdb/doc/ChangeLog:

	* gdb.texinfo (Symbols): Document new 'info module variables' and
	'info module functions' commands.

gdb/testsuite/ChangeLog:

	* gdb.fortran/info-modules.exp: Update expected results, and add
	additional tests for 'info module functinos', and 'info module
	variables'.
	* gdb.fortran/info-types.exp: Update expected results.
	* gdb.fortran/info-types.f90: Extend testcase with additional
	module variables and functions.

Change-Id: I8c2960640e2e101b77eff54027d687e21ec22e2b
---
 gdb/ChangeLog                              |  18 ++
 gdb/NEWS                                   |  14 ++
 gdb/doc/ChangeLog                          |   5 +
 gdb/doc/gdb.texinfo                        |  19 ++
 gdb/symtab.c                               | 337 +++++++++++++++++++++++++++++
 gdb/symtab.h                               |  16 ++
 gdb/testsuite/ChangeLog                    |   9 +
 gdb/testsuite/gdb.fortran/info-modules.exp | 123 ++++++++++-
 gdb/testsuite/gdb.fortran/info-types-2.f90 |  16 ++
 gdb/testsuite/gdb.fortran/info-types.exp   |   6 +-
 gdb/testsuite/gdb.fortran/info-types.f90   |  15 ++
 11 files changed, 575 insertions(+), 3 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index e721f3bde44..276e9618afa 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -151,6 +151,20 @@ info modules [-q] [REGEXP]
   Return a list of Fortran modules matching REGEXP, or all modules if
   no REGEXP is given.
 
+info module functions [-q] [-m MODULE_REGEXP] [-t TYPE_REGEXP] [REGEXP]
+  Return a list of functions within all modules, grouped by module.
+  The list of functions can be restricted with the optional regular
+  expressions.  MODULE_REGEXP matches against the module name,
+  TYPE_REGEXP matches against the function type signature, and REGEXP
+  matches against the function name.
+
+info module variables [-q] [-m MODULE_REGEXP] [-t TYPE_REGEXP] [REGEXP]
+  Return a list of variables within all modules, grouped by module.
+  The list of variables can be restricted with the optional regular
+  expressions.  MODULE_REGEXP matches against the module name,
+  TYPE_REGEXP matches against the variable type, and REGEXP matches
+  against the variable name.
+
 * Changed commands
 
 help
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 3f97707c4c1..c05955cbb68 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -18794,6 +18794,25 @@
 printing header information and messages explaining why no modules
 have been printed.
 
+@kindex info module
+@cindex Fortran modules, information about
+@cindex functions and variables by Fortran module
+@cindex module functions and variables
+@item info module functions [-q] [-m @var{module-regexp}] [-t @var{type-regexp}] [@var{regexp}]
+@itemx info module variables [-q] [-m @var{module-regexp}] [-t @var{type-regexp}] [@var{regexp}]
+List all functions or variables within all Fortran modules.  The set
+of functions or variables listed can be limited by providing some or
+all of the optional regular expressions.  If @var{module-regexp} is
+provided, then only Fortran modules matching @var{module-regexp} will
+be searched.  Only functions or variables whose type matches the
+optional regular expression @var{type-regexp} will be listed.  And
+only functions or variables whose name matches the optional regular
+expression @var{regexp} will be listed.
+
+The optional flag @samp{-q}, which stands for @samp{quiet}, disables
+printing header information and messages explaining why no functions
+or variables have been printed.
+
 @kindex info classes
 @cindex Objective-C, classes and selectors
 @item info classes
diff --git a/gdb/symtab.c b/gdb/symtab.c
index f41ea3290df..67938cb818e 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -6332,6 +6332,304 @@ 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);
+
+  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)
 {
@@ -6394,6 +6692,45 @@ Options:\n\
 		_("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."));
 
diff --git a/gdb/symtab.h b/gdb/symtab.h
index ba8df9191ff..6bd8873042f 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -2070,6 +2070,22 @@ extern std::vector<symbol_search> search_symbols (const char *,
 						  int,
 						  const char **,
 						  bool);
+
+/* When searching for Fortran symbols within modules (functions/variables)
+   we return a vector of this type.  The first item in the pair is the
+   module symbol, and the second item is the symbol for the function or
+   variable we found.  */
+typedef std::pair<symbol_search,symbol_search> module_symbol_search;
+
+/* Searches the symbols to find function and variables symbols (depending
+   on KIND) within Fortran modules.  The MODULE_REGEXP matches against the
+   name of the module, REGEXP matches against the name of the symbol within
+   the module, and TYPE_REGEXP matches against the type of the symbol
+   within the module.  */
+extern std::vector<module_symbol_search> search_module_symbols
+	(const char *module_regexp, const char *regexp,
+	 const char *type_regexp, search_domain kind);
+
 extern bool treg_matches_sym_type_name (const compiled_regex &treg,
 					const struct symbol *sym);
 
diff --git a/gdb/testsuite/gdb.fortran/info-modules.exp b/gdb/testsuite/gdb.fortran/info-modules.exp
index f961d28b000..43570066d2f 100644
--- a/gdb/testsuite/gdb.fortran/info-modules.exp
+++ b/gdb/testsuite/gdb.fortran/info-modules.exp
@@ -13,7 +13,8 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-# This file tests 'info modules'.
+# This file tests 'info modules', 'info module functions', and 'info
+# module variables'.
 
 load_lib "fortran.exp"
 
@@ -31,6 +32,12 @@ if { ![runto MAIN__] } {
     continue
 }
 
+set logical4 [fortran_logical4]
+set integer4 [fortran_int4]
+set real4 [fortran_real4]
+
+# Test 'info modules' command.
+
 gdb_test "info modules" \
     [multi_line \
 	 "All defined modules:" \
@@ -64,3 +71,117 @@ gdb_test "info modules mod" \
 	 "" \
 	 "File .*${srcfile}:" \
 	 "16:\[\t \]+mod1" ]
+
+# Test 'info module functions'.
+
+gdb_test "info module functions" \
+    [multi_line \
+	 "All functions in all modules:" \
+	 "" \
+	 "Module \"mod2\":" \
+	 "" \
+	 "File .*${srcfile2}:" \
+	 "22:\[\t \]+void mod2::sub_m2_a\\(${integer4}, ${logical4}\\);" \
+	 "30:\[\t \]+${logical4} mod2::sub_m2_b\\(${real4}\\);" \
+	 "" \
+	 "Module \"mod1\":" \
+	 "" \
+	 "File .*${srcfile}:" \
+	 "35:\[\t \]+void mod1::__copy_mod1_M1t1\\(Type m1t1, Type m1t1\\);" \
+	 "25:\[\t \]+void mod1::sub_m1_a\\(${integer4}\\);" \
+	 "31:\[\t \]+${integer4} mod1::sub_m1_b\\(void\\);" ]
+
+gdb_test "info module functions -m mod1" \
+    [multi_line \
+	 "All functions in all modules matching regular expression \"mod1\":" \
+	 "" \
+	 "Module \"mod1\":" \
+	 "" \
+	 "File .*:" \
+	 "35:\[\t \]+void mod1::__copy_mod1_M1t1\\(Type m1t1, Type m1t1\\);" \
+	 "25:\[\t \]+void mod1::sub_m1_a\\(${integer4}\\);" \
+	 "31:\[\t \]+${integer4} mod1::sub_m1_b\\(void\\);" ]
+
+gdb_test "info module functions -t integer" \
+    [multi_line \
+	 "All functions with type matching regular expression \"integer\" in all modules:" \
+	 "" \
+	 "Module \"mod2\":" \
+	 "" \
+	 "File .*${srcfile2}:" \
+	 "22:\[\t \]+void mod2::sub_m2_a\\(${integer4}, ${logical4}\\);" \
+	 "" \
+	 "Module \"mod1\":" \
+	 "" \
+	 "File .*${srcfile}:" \
+	 "25:\[\t \]+void mod1::sub_m1_a\\(${integer4}\\);" \
+	 "31:\[\t \]+${integer4} mod1::sub_m1_b\\(void\\);" ]
+
+# Test 'info module variables'.
+
+gdb_test "info module variables" \
+    [multi_line \
+	 "All variables in all modules:" \
+	 "" \
+	 "Module \"mod2\":" \
+	 "" \
+	 "File .*${srcfile2}:" \
+	 "19:\[\t \]+${integer4} mod2::mod2_var_1;" \
+	 "20:\[\t \]+${real4} mod2::mod2_var_2;" \
+	 "" \
+	 "Module \"mod1\":" \
+	 "" \
+	 "File .*${srcfile}:" \
+	 "35:\[\t \]+Type m1t1 mod1::__def_init_mod1_M1t1;" \
+	 "35:\[\t \]+Type __vtype_mod1_M1t1 mod1::__vtab_mod1_M1t1;" \
+	 "21:\[\t \]+${real4} mod1::mod1_var_1;" \
+	 "22:\[\t \]+${integer4} mod1::mod1_var_2;" ]
+
+gdb_test "info module variables -t real" \
+    [multi_line \
+	 "All variables with type matching regular expression \"real\" in all modules:" \
+	 "" \
+	 "Module \"mod2\":" \
+	 "" \
+	 "File .*:" \
+	 "20:\[\t \]+${real4} mod2::mod2_var_2;" \
+	 "" \
+	 "Module \"mod1\":" \
+	 "" \
+	 "File .*:" \
+	 "21:\[\t \]+${real4} mod1::mod1_var_1;" ]
+
+gdb_test "info module variables -m mod2" \
+    [multi_line \
+	 "All variables in all modules matching regular expression \"mod2\":" \
+	 "" \
+	 "Module \"mod2\":" \
+	 "" \
+	 "File .*${srcfile2}:" \
+	 "19:\[\t \]+${integer4} mod2::mod2_var_1;" \
+	 "20:\[\t \]+${real4} mod2::mod2_var_2;" ]
+
+gdb_test "info module variables -m mod2 -t real" \
+    [multi_line \
+	 "All variables with type matching regular expression \"real\"" \
+	 "	in all modules matching regular expression \"mod2\":" \
+	 "" \
+	 "Module \"mod2\":" \
+	 "" \
+	 "File .*${srcfile2}:" \
+	 "20:\[\t \]+${real4} mod2::mod2_var_2;" ]
+
+gdb_test "info module variables _1" \
+    [multi_line \
+	 "All variables matching regular expression \"_1\" in all modules:" \
+	 "" \
+	 "Module \"mod2\":" \
+	 "" \
+	 "File .*:" \
+	 "19:\[\t \]+${integer4} mod2::mod2_var_1;" \
+	 "" \
+	 "Module \"mod1\":" \
+	 "" \
+	 "File .*:" \
+	 "21:\[\t \]+${real4} mod1::mod1_var_1;" ]
+
diff --git a/gdb/testsuite/gdb.fortran/info-types-2.f90 b/gdb/testsuite/gdb.fortran/info-types-2.f90
index a4044184233..3fe2259da49 100644
--- a/gdb/testsuite/gdb.fortran/info-types-2.f90
+++ b/gdb/testsuite/gdb.fortran/info-types-2.f90
@@ -17,4 +17,20 @@
 ! mod2 is defined.
 module mod2
   integer :: mod2_var_1 = 123
+  real, parameter :: mod2_var_2 = 0.5
+contains
+  subroutine sub_m2_a(a, b)
+    integer :: a
+    logical :: b
+    print*, "sub_m2_a = ", abc
+    print*, "a = ", a
+    print*, "b = ", b
+  end subroutine sub_m2_a
+
+  logical function sub_m2_b(x)
+    real :: x
+    print*, "sub_m2_b = ", cde
+    print*, "x = ", x
+    sub_m2_b = .true.
+  end function sub_m2_b
 end module mod2
diff --git a/gdb/testsuite/gdb.fortran/info-types.exp b/gdb/testsuite/gdb.fortran/info-types.exp
index 1707de88bda..f19fbf2ef1e 100644
--- a/gdb/testsuite/gdb.fortran/info-types.exp
+++ b/gdb/testsuite/gdb.fortran/info-types.exp
@@ -35,6 +35,7 @@ set integer4 [fortran_int4]
 set integer8 [fortran_int8]
 set logical4 [fortran_logical4]
 set character1 [fortran_character1]
+set real4 [fortran_real4]
 
 gdb_test "info types" \
     [multi_line \
@@ -45,7 +46,8 @@ gdb_test "info types" \
 	 "\[\t \]+${integer4}" \
 	 "(\[\t \]+${integer8}" \
 	 ")?\[\t \]+${logical4}" \
-	 "(20:\[\t \]+Type __vtype_mod1_M1t1;" \
+	 "(35:\[\t \]+Type __vtype_mod1_M1t1;" \
 	 ")?$decimal:\[\t \]+Type m1t1;" \
-	 "22:\[\t \]+Type s1;(" \
+	 "\[\t \]+${real4}" \
+	 "37:\[\t \]+Type s1;(" \
 	 ".*)?"]
diff --git a/gdb/testsuite/gdb.fortran/info-types.f90 b/gdb/testsuite/gdb.fortran/info-types.f90
index ec52ef98efc..d3513aca304 100644
--- a/gdb/testsuite/gdb.fortran/info-types.f90
+++ b/gdb/testsuite/gdb.fortran/info-types.f90
@@ -17,6 +17,21 @@ module mod1
   type :: m1t1
      integer :: b
   end type m1t1
+
+  real :: mod1_var_1 = 1.0
+  integer, parameter :: mod1_var_2 = 456
+
+contains
+  subroutine sub_m1_a(arg)
+    integer :: arg
+    print*, "sub_m1_a"
+    print*, "arg = ", arg
+  end subroutine sub_m1_a
+
+  integer function sub_m1_b()
+    print*, "sub_m1_b"
+    sub_m1_b = 3
+  end function sub_m1_b
 end module mod1
 
 program info_types_test
-- 
2.14.5

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCHv3 3/9] gdb: Don't print a newline in language la_print_typedef methods
  2019-10-16 23:28 [PATCHv3 0/9] Fortran 'info module *' commands and MI '-symbol-info-*' commands Andrew Burgess
                   ` (5 preceding siblings ...)
  2019-10-16 23:28 ` [PATCHv3 2/9] gdb: Add new commands to list module variables and functions Andrew Burgess
@ 2019-10-16 23:28 ` Andrew Burgess
  2019-10-16 23:28 ` [PATCHv3 1/9] gdb/fortran: Add new 'info modules' command Andrew Burgess
  2019-10-16 23:28 ` [PATCHv3 5/9] gdb: Split print_symbol_info into two parts Andrew Burgess
  8 siblings, 0 replies; 10+ messages in thread
From: Andrew Burgess @ 2019-10-16 23:28 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

When calling the language la_print_typedef method, don't include a
newline at the end, instead print the newline from the users of
la_print_typedef.

This change will be useful in a later commit when the output from
la_print_typedef will be placed into an MI output field, in which case
the trailing newline is not required.

There should be no user visible changes after this commit.

gdb/ChangeLog:

	* ada-typeprint.c (ada_print_typedef): Don't print newline at the
	end.
	* c-typeprint.c (c_print_typedef): Likewise.
	* f-typeprint.c (f_print_typedef): Likewise.
	* m2-typeprint.c (m2_print_typedef): Likewise.
	* p-typeprint.c (pascal_print_typedef): Likewise.
	* rust-lang.c (rust_print_typedef): Likewise.
	* symtab.c (print_symbol_info): Print a newline after calling
	typedef_print.

Change-Id: I6e697ea1ec0eadaa31aefaea959b2055188d680d
---
 gdb/ChangeLog       | 12 ++++++++++++
 gdb/ada-typeprint.c |  1 -
 gdb/c-typeprint.c   |  2 +-
 gdb/f-typeprint.c   |  1 -
 gdb/m2-typeprint.c  |  2 +-
 gdb/p-typeprint.c   |  2 +-
 gdb/rust-lang.c     |  2 +-
 gdb/symtab.c        |  6 ++----
 8 files changed, 18 insertions(+), 10 deletions(-)

diff --git a/gdb/ada-typeprint.c b/gdb/ada-typeprint.c
index c2461660ad4..4c2e37c688b 100644
--- a/gdb/ada-typeprint.c
+++ b/gdb/ada-typeprint.c
@@ -954,5 +954,4 @@ ada_print_typedef (struct type *type, struct symbol *new_symbol,
 {
   type = ada_check_typedef (type);
   ada_print_type (type, "", stream, 0, 0, &type_print_raw_options);
-  fprintf_filtered (stream, "\n");
 }
diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c
index 1a37c4edfb8..e0f1714da11 100644
--- a/gdb/c-typeprint.c
+++ b/gdb/c-typeprint.c
@@ -211,7 +211,7 @@ c_print_typedef (struct type *type,
 		 SYMBOL_LINKAGE_NAME (new_symbol)) != 0
       || TYPE_CODE (SYMBOL_TYPE (new_symbol)) == TYPE_CODE_TYPEDEF)
     fprintf_filtered (stream, " %s", SYMBOL_PRINT_NAME (new_symbol));
-  fprintf_filtered (stream, ";\n");
+  fprintf_filtered (stream, ";");
 }
 
 /* If TYPE is a derived type, then print out derivation information.
diff --git a/gdb/f-typeprint.c b/gdb/f-typeprint.c
index 0093aebddc2..027bcdde0f9 100644
--- a/gdb/f-typeprint.c
+++ b/gdb/f-typeprint.c
@@ -54,7 +54,6 @@ f_print_typedef (struct type *type, struct symbol *new_symbol,
 {
   type = check_typedef (type);
   f_print_type (type, "", stream, 0, 0, &type_print_raw_options);
-  fprintf_filtered (stream, "\n");
 }
 
 /* LEVEL is the depth to indent lines by.  */
diff --git a/gdb/m2-typeprint.c b/gdb/m2-typeprint.c
index 3c1a8d2aed3..e81a9e56888 100644
--- a/gdb/m2-typeprint.c
+++ b/gdb/m2-typeprint.c
@@ -170,7 +170,7 @@ m2_print_typedef (struct type *type, struct symbol *new_symbol,
   else
     fprintf_filtered (stream, "<builtin> = ");
   type_print (type, "", stream, 0);
-  fprintf_filtered (stream, ";\n");
+  fprintf_filtered (stream, ";");
 }
 
 /* m2_type_name - if a, type, has a name then print it.  */
diff --git a/gdb/p-typeprint.c b/gdb/p-typeprint.c
index fadc44eaee8..da30d4a3ac2 100644
--- a/gdb/p-typeprint.c
+++ b/gdb/p-typeprint.c
@@ -101,7 +101,7 @@ pascal_print_typedef (struct type *type, struct symbol *new_symbol,
   fprintf_filtered (stream, "type ");
   fprintf_filtered (stream, "%s = ", SYMBOL_PRINT_NAME (new_symbol));
   type_print (type, "", stream, 0);
-  fprintf_filtered (stream, ";\n");
+  fprintf_filtered (stream, ";");
 }
 
 /* If TYPE is a derived type, then print out derivation information.
diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
index cef0a9cb092..838d9019adf 100644
--- a/gdb/rust-lang.c
+++ b/gdb/rust-lang.c
@@ -831,7 +831,7 @@ rust_print_typedef (struct type *type,
   type = check_typedef (type);
   fprintf_filtered (stream, "type %s = ", SYMBOL_PRINT_NAME (new_symbol));
   type_print (type, "", stream, 0);
-  fprintf_filtered (stream, ";\n");
+  fprintf_filtered (stream, ";");
 }
 
 /* la_print_type implementation for Rust.  */
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 67938cb818e..21ac57c39a9 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4766,10 +4766,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
-- 
2.14.5

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCHv3 4/9] gdb: Introduce symbol_search_spec
  2019-10-16 23:28 [PATCHv3 0/9] Fortran 'info module *' commands and MI '-symbol-info-*' commands Andrew Burgess
@ 2019-10-16 23:28 ` Andrew Burgess
  2019-10-16 23:28 ` [PATCHv3 6/9] gdb/mi: Add new commands -symbol-info-{functions,variables,types} Andrew Burgess
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Andrew Burgess @ 2019-10-16 23:28 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

Introduce a new structure to wrap up the parameters needed for
search_symbols.  We already pass a lot of parameters to
search_symbols and a later commit is going to add more.  As part of
this conversion the list of filenames has been converted to a
std::vector.

There should be no user visible changes after this commit.

gdb/ChangeLog:

	* python/python.c (gdbpy_rbreak): Convert to using
	search_symbols_spec.
	* symtab.c (file_matches): Convert return type to bool, change
	file list to std::vector.
	(search_symbols): Update to use search_symbols_spec, and take
	account of the changes to file_matches.
	(symtab_symbol_info): Convert to using search_symbols_spec.
	(rbreak_command): Likewise.
	(search_module_symbols): Likewise.
	* symtab.h (struct search_symbols_spec): New struct.
	(search_symbols): Update parameters.

Change-Id: I488ab292a892d9e9e84775c632c5f198b6ad3710
---
 gdb/ChangeLog       |  14 +++++++
 gdb/python/python.c |  48 +++++++++++------------
 gdb/symtab.c        | 107 +++++++++++++++++++++-------------------------------
 gdb/symtab.h        |  52 ++++++++++++++++++++++---
 4 files changed, 127 insertions(+), 94 deletions(-)

diff --git a/gdb/python/python.c b/gdb/python/python.c
index ddf0e72d26f..05ad038865a 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -645,19 +645,6 @@ execute_gdb_command (PyObject *self, PyObject *args, PyObject *kw)
 static PyObject *
 gdbpy_rbreak (PyObject *self, PyObject *args, PyObject *kw)
 {
-  /* A simple type to ensure clean up of a vector of allocated strings
-     when a C interface demands a const char *array[] type
-     interface.  */
-  struct symtab_list_type
-  {
-    ~symtab_list_type ()
-    {
-      for (const char *elem: vec)
-	xfree ((void *) elem);
-    }
-    std::vector<const char *> vec;
-  };
-
   char *regex = NULL;
   std::vector<symbol_search> symbols;
   unsigned long count = 0;
@@ -667,7 +654,6 @@ gdbpy_rbreak (PyObject *self, PyObject *args, PyObject *kw)
   unsigned int throttle = 0;
   static const char *keywords[] = {"regex","minsyms", "throttle",
 				   "symtabs", NULL};
-  symtab_list_type symtab_paths;
 
   if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "s|O!IO", keywords,
 					&regex, &PyBool_Type,
@@ -684,6 +670,26 @@ gdbpy_rbreak (PyObject *self, PyObject *args, PyObject *kw)
       minsyms_p = cmp;
     }
 
+  /* A wrapper around search_symbols_spec in order to call free the
+     strings held in the filenames vector.  */
+  struct python_rbreak_search_symbols_spec
+  {
+    search_symbols_spec spec;
+
+    python_rbreak_search_symbols_spec (const char *regex)
+      : spec (FUNCTIONS_DOMAIN, regex)
+    { /* Nothing.  */ }
+
+    ~python_rbreak_search_symbols_spec ()
+    {
+      for (const char *elem: spec.filenames)
+	xfree ((void *) elem);
+    }
+  };
+
+  /* The search spec.  */
+  python_rbreak_search_symbols_spec spec (regex);
+
   /* The "symtabs" keyword is any Python iterable object that returns
      a gdb.Symtab on each iteration.  If specified, iterate through
      the provided gdb.Symtabs and extract their full path.  As
@@ -729,20 +735,12 @@ gdbpy_rbreak (PyObject *self, PyObject *args, PyObject *kw)
 
 	  /* Make sure there is a definite place to store the value of
 	     filename before it is released.  */
-	  symtab_paths.vec.push_back (nullptr);
-	  symtab_paths.vec.back () = filename.release ();
+	  spec.spec.filenames.push_back (nullptr);
+	  spec.spec.filenames.back () = filename.release ();
 	}
     }
 
-  if (symtab_list)
-    {
-      const char **files = symtab_paths.vec.data ();
-
-      symbols = search_symbols (regex, FUNCTIONS_DOMAIN, NULL,
-				symtab_paths.vec.size (), files, false);
-    }
-  else
-    symbols = search_symbols (regex, FUNCTIONS_DOMAIN, NULL, 0, NULL, false);
+  symbols = search_symbols (spec.spec);
 
   /* Count the number of symbols (both symbols and optionally minimal
      symbols) so we can correctly check the throttle limit.  */
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 21ac57c39a9..b7b65b98ac8 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4331,26 +4331,23 @@ 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
+   non-zero 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.size () == 0)
+    return 1;
 
-  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 1;
     }
-  else if (nfiles == 0)
-    return 1;
+
   return 0;
 }
 
@@ -4428,31 +4425,19 @@ 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)
+search_symbols (const search_symbols_spec &search_spec)
 {
+  /* Unpack the search spec.  */
+  const char *regexp = search_spec.symbol_regexp;
+  enum search_domain kind = search_spec.kind;
+  const char *t_regexp = search_spec.type_regexp;
+  int nfiles = search_spec.filenames.size ();
+  bool exclude_minsyms = search_spec.exclude_minsyms;
+
+  /* The search.  */
   const struct blockvector *bv;
   const struct block *b;
   int i = 0;
@@ -4535,8 +4520,12 @@ search_symbols (const char *regexp, enum search_domain kind,
      the machinery below.  */
   expand_symtabs_matching ([&] (const char *filename, bool basenames)
 			   {
-			     return file_matches (filename, files, nfiles,
-						  basenames);
+			     /* EXPAND_SYMTABS_MATCHING expects a callback
+				that returns an integer, not a boolean as
+				FILE_MATCHES does.  */
+			     return file_matches (filename,
+						  search_spec.filenames,
+						  basenames) ? 1 : 0;
 			   },
 			   lookup_name_info::match_any (),
 			   [&] (const char *symname)
@@ -4620,12 +4609,13 @@ 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,
+				     search_spec.filenames, false)
 		       || ((basenames_may_differ
 			    || file_matches (lbasename (real_symtab->filename),
-					     files, nfiles, 1))
+					     search_spec.filenames, true))
 			   && file_matches (symtab_to_fullname (real_symtab),
-					    files, nfiles, 0)))
+					    search_spec.filenames, false)))
 		      && ((!preg.has_value ()
 			   || preg->exec (SYMBOL_NATURAL_NAME (sym), 0,
 					  NULL, 0) == 0)
@@ -4836,9 +4826,8 @@ symtab_symbol_info (bool quiet, bool exclude_minsyms,
     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);
+  search_symbols_spec spec (kind, regexp, t_regexp, exclude_minsyms);
+  std::vector<symbol_search> symbols = search_symbols (spec);
 
   if (!quiet)
     {
@@ -5077,11 +5066,9 @@ 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, ':');
 
@@ -5097,17 +5084,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);
+  search_symbols_spec spec (FUNCTIONS_DOMAIN, regexp);
+  if (file_name != nullptr)
+    spec.filenames.push_back (file_name);
+  std::vector<symbol_search> symbols = search_symbols (spec);
 
   scoped_rbreak_breakpoints finalize;
   for (const symbol_search &p : symbols)
@@ -6352,17 +6336,14 @@ search_module_symbols (const char *module_regexp, const char *regexp,
   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);
+  search_symbols_spec spec1 (MODULES_DOMAIN, module_regexp, nullptr, true);
+  std::vector<symbol_search> modules = search_symbols (spec1);
 
   /* 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);
+  search_symbols_spec spec2 (kind, regexp, type_regexp, true);
+  std::vector<symbol_search> symbols = search_symbols (spec2);
 
   /* Now iterate over all MODULES, checking to see which items from
      SYMBOLS are in each module.  */
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 6bd8873042f..f1c7db22505 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -2064,12 +2064,52 @@ private:
 				  const symbol_search &sym_b);
 };
 
-extern std::vector<symbol_search> search_symbols (const char *,
-						  enum search_domain,
-						  const char *,
-						  int,
-						  const char **,
-						  bool);
+/* When searching for symbols using the SEARCH_SYMBOLS function, one of
+   these structures is used as the search specification.  */
+struct search_symbols_spec
+{
+  /* The kind of symbols are we searching for.
+     VARIABLES_DOMAIN - Search all symbols, excluding functions, type
+                        names, and constants (enums).
+     FUNCTIONS_DOMAIN - Search all functions..
+     TYPES_DOMAIN     - Search all type names.
+     MODULES_DOMAIN   - Search all Fortran modules.
+     ALL_DOMAIN       - Not valid for this function.  */
+  enum search_domain kind;
+
+  /* Regular expression to match against the symbol name.  */
+  const char *symbol_regexp = nullptr;
+
+  /* Regular expression to match against the type of the symbol.  */
+  const char *type_regexp = nullptr;
+
+  /* When this flag is false then minsyms that match SYMBOL_REGEXP will be
+     included in the results, otherwise they are excluded.  */
+  bool exclude_minsyms = false;
+
+  /* The set of source files to search in for matching symbols.  */
+  std::vector<const char *> filenames;
+
+  /* Constructor.  */
+  search_symbols_spec (enum search_domain kind,
+		       const char *symbol_regexp = nullptr,
+		       const char *type_regexp = nullptr,
+		       bool exclude_minsyms = false)
+    : kind (kind),
+      symbol_regexp (symbol_regexp),
+      type_regexp (type_regexp),
+      exclude_minsyms (exclude_minsyms)
+  { /* Nothing.  */ }
+};
+
+/* Search the symbol table for matches as defined by SEARCH_SPEC.
+
+   Within each file the results are sorted locally; each symtab's global
+   and static blocks are separately alphabetized.  Duplicate entries are
+   removed.  */
+
+extern std::vector<symbol_search> search_symbols
+	(const struct search_symbols_spec &search_spec);
 
 /* When searching for Fortran symbols within modules (functions/variables)
    we return a vector of this type.  The first item in the pair is the
-- 
2.14.5

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2019-10-16 23:28 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-16 23:28 [PATCHv3 0/9] Fortran 'info module *' commands and MI '-symbol-info-*' commands Andrew Burgess
2019-10-16 23:28 ` [PATCHv3 4/9] gdb: Introduce symbol_search_spec Andrew Burgess
2019-10-16 23:28 ` [PATCHv3 6/9] gdb/mi: Add new commands -symbol-info-{functions,variables,types} Andrew Burgess
2019-10-16 23:28 ` [PATCHv3 7/9] gdb/mi: Add -symbol-info-modules command Andrew Burgess
2019-10-16 23:28 ` [PATCHv3 8/9] gdb/mi: Add -symbol-info-module-{variables,functions} Andrew Burgess
2019-10-16 23:28 ` [PATCHv3 9/9] gdb/mi: Add -max-results parameter to some -symbol-info-* commands Andrew Burgess
2019-10-16 23:28 ` [PATCHv3 2/9] gdb: Add new commands to list module variables and functions Andrew Burgess
2019-10-16 23:28 ` [PATCHv3 3/9] gdb: Don't print a newline in language la_print_typedef methods Andrew Burgess
2019-10-16 23:28 ` [PATCHv3 1/9] gdb/fortran: Add new 'info modules' command Andrew Burgess
2019-10-16 23:28 ` [PATCHv3 5/9] gdb: Split print_symbol_info into two parts Andrew Burgess

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).