public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [review v2] gdb/mi: Add -max-results parameter to some -symbol-info-* commands
       [not found] <gerrit.1571909344000.I90a28feb55b388fb46461a096c5db08b6b0bd427@gnutoolchain-gerrit.osci.io>
@ 2019-11-01  1:35 ` Andrew Burgess (Code Review)
  2019-11-08  0:50 ` [review v3] " Andrew Burgess (Code Review)
                   ` (25 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrew Burgess (Code Review) @ 2019-11-01  1:35 UTC (permalink / raw)
  To: gdb-patches

Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/269
......................................................................

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

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_spec::is_suitable_msymbol): New function.
	(search_symbols_spec::expand_symtabs): New function.
	(search_symbols_spec::add_matching_symbols): New function.
	(search_symbols_spec::add_matching_msymbols): New function.
	(search_symbols_spec::search_symbols): Move most of the content
	into the new functions above, and call them as needed.
	* symtab.h: Add 'set' include.
	(struct search_symbols_spec) <max_search_results>: New member
	variable.
	(struct search_symbols_spec) <expand_symtabs>: New member
	function.
	(struct search_symbols_spec) <add_matching_symbols>: New member
	function.
	(struct search_symbols_spec) <add_matching_msymbols>: New member
	function.
	(struct search_symbols_spec) <is_suitable_msymbol>: New member
	function.

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
---
M gdb/ChangeLog
M gdb/doc/ChangeLog
M gdb/doc/gdb.texinfo
M gdb/mi/mi-symbol-cmds.c
M gdb/symtab.c
M gdb/symtab.h
M gdb/testsuite/ChangeLog
M gdb/testsuite/gdb.mi/mi-sym-info.exp
8 files changed, 425 insertions(+), 218 deletions(-)



diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index b11ceda..4f41d69 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,33 @@
 2019-11-01  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* 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_spec::is_suitable_msymbol): New function.
+	(search_symbols_spec::expand_symtabs): New function.
+	(search_symbols_spec::add_matching_symbols): New function.
+	(search_symbols_spec::add_matching_msymbols): New function.
+	(search_symbols_spec::search_symbols): Move most of the content
+	into the new functions above, and call them as needed.
+	* symtab.h: Add 'set' include.
+	(struct search_symbols_spec) <max_search_results>: New member
+	variable.
+	(struct search_symbols_spec) <expand_symtabs>: New member
+	function.
+	(struct search_symbols_spec) <add_matching_symbols>: New member
+	function.
+	(struct search_symbols_spec) <add_matching_msymbols>: New member
+	function.
+	(struct search_symbols_spec) <is_suitable_msymbol>: New member
+	function.
+
+2019-11-01  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* 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.
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 2901705..971bc94 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,5 +1,10 @@
 2019-11-01  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* doc/gdb.texinfo (GDB/MI Symbol Query): Add documentation of
+	-max-results to some -symbol-info-* commands.
+
+2019-11-01  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* doc/gdb.texinfo (GDB/MI Symbol Query): Document new MI command
 	-symbol-info-module-functions and -symbol-info-module-variables.
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 6219699..0f6d3b5 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -33864,6 +33864,7 @@
  -symbol-info-functions [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
 @end smallexample
 
 @noindent
@@ -33879,6 +33880,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}.
@@ -34110,6 +34116,8 @@
 
 @smallexample
  -symbol-info-modules [--name @var{name_regexp}]
+                      [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34120,6 +34128,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}.
@@ -34164,6 +34177,8 @@
 
 @smallexample
  -symbol-info-types [--name @var{name_regexp}]
+                    [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34177,6 +34192,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}.
@@ -34224,6 +34244,8 @@
  -symbol-info-variables [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34239,6 +34261,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 0b14cb2..c62b22e 100644
--- a/gdb/mi/mi-symbol-cmds.c
+++ b/gdb/mi/mi-symbol-cmds.c
@@ -248,10 +248,12 @@
 
 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)
 {
   /* 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 = spec.search_symbols ();
 
   mi_symbol_info_emitter emitter (current_uiout);
@@ -268,19 +270,21 @@
 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 }
   };
 
@@ -306,10 +310,19 @@
 	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.
@@ -443,15 +456,17 @@
 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 }
   };
 
@@ -469,10 +484,19 @@
 	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.  */
@@ -480,15 +504,17 @@
 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 }
   };
 
@@ -506,10 +532,19 @@
 	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 1a71ef4..4ff3c5a 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4359,8 +4359,8 @@
   return false;
 }
 
-/* Helper function for sort_search_symbols_remove_dups and qsort.  Can only
-   sort symbols, not minimal symbols.  */
+/* Helper function for std::sort on symbol_search objects.  Can only sort
+   symbols, not minimal symbols.  */
 
 int
 symbol_search::compare_search_syms (const symbol_search &sym_a,
@@ -4422,15 +4422,242 @@
   return treg.exec (printed_sym_type_name.c_str (), 0, NULL, 0) == 0;
 }
 
+/* See symtab.h.  */
 
-/* Sort the symbols in RESULT and remove duplicates.  */
-
-static void
-sort_search_symbols_remove_dups (std::vector<symbol_search> *result)
+bool
+search_symbols_spec::is_suitable_msymbol
+	(const enum search_domain kind, const minimal_symbol *msymbol)
 {
-  std::sort (result->begin (), result->end ());
-  result->erase (std::unique (result->begin (), result->end ()),
-		 result->end ());
+  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};
+
+  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);
+}
+
+/* See symtab.h.  */
+
+bool
+search_symbols_spec::expand_symtabs
+	(objfile *objfile, const gdb::optional<compiled_regex> &preg) const
+{
+  enum search_domain kind = m_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, 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 (filenames.empty ()
+      && (kind == VARIABLES_DOMAIN || kind == FUNCTIONS_DOMAIN))
+    {
+      for (minimal_symbol *msymbol : objfile->msymbols ())
+	{
+	  QUIT;
+
+	  if (msymbol->created_by_gdb)
+	    continue;
+
+	  if (is_suitable_msymbol (kind, msymbol))
+	    {
+	      if (!preg.has_value ()
+		  || preg->exec (MSYMBOL_NATURAL_NAME (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;
+}
+
+/* See symtab.h.  */
+bool
+search_symbols_spec::add_matching_symbols
+	(objfile *objfile,
+	 const gdb::optional<compiled_regex> &preg,
+	 const gdb::optional<compiled_regex> &treg,
+	 std::set<symbol_search> *result_set) const
+{
+  enum search_domain kind = m_kind;
+
+  /* Add matching symbols (if not already present).  */
+  for (compunit_symtab *cust : objfile->compunits ())
+    {
+      const struct blockvector *bv  = COMPUNIT_BLOCKVECTOR (cust);
+
+      for (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, filenames, false)
+		   || ((basenames_may_differ
+			|| file_matches (lbasename (real_symtab->filename),
+					 filenames, true))
+		       && file_matches (symtab_to_fullname (real_symtab),
+					filenames, false)))
+		  && ((!preg.has_value ()
+		       || preg->exec (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 (max_search_results == -1
+		      || result_set->size () < 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;
+}
+
+/* See symtab.h.  */
+
+bool
+search_symbols_spec::add_matching_msymbols
+	(objfile *objfile, const gdb::optional<compiled_regex> &preg,
+	 std::vector<symbol_search> *results) const
+{
+  enum search_domain kind = m_kind;
+
+  for (minimal_symbol *msymbol : objfile->msymbols ())
+    {
+      QUIT;
+
+      if (msymbol->created_by_gdb)
+	continue;
+
+      if (is_suitable_msymbol (kind, msymbol))
+	{
+	  if (!preg.has_value ()
+	      || preg->exec (MSYMBOL_NATURAL_NAME (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 (max_search_results == -1
+			  || (results->size () < max_search_results))
+			results->emplace_back (GLOBAL_BLOCK, msymbol, objfile);
+		      else
+			return false;
+		    }
+		}
+	    }
+	}
+    }
+
+  return true;
 }
 
 /* See symtab.h.  */
@@ -4441,37 +4668,11 @@
   const char *regexp = m_symbol_regexp;
   const char *t_regexp = m_type_regexp;
   enum search_domain kind = m_kind;
-  bool exclude_minsyms = m_exclude_minsyms;
-  int nfiles = filenames.size ();
-  const struct blockvector *bv;
-  const struct block *b;
-  int i = 0;
-  struct block_iterator iter;
-  struct symbol *sym;
-  int found_misc = 0;
-  static const enum minimal_symbol_type types[]
-    = {mst_data, mst_text, mst_unknown};
-  static const enum minimal_symbol_type types2[]
-    = {mst_bss, mst_file_text, mst_unknown};
-  static const enum minimal_symbol_type types3[]
-    = {mst_file_data, mst_solib_trampoline, mst_unknown};
-  static const enum minimal_symbol_type types4[]
-    = {mst_file_bss, mst_text_gnu_ifunc, mst_unknown};
-  enum minimal_symbol_type ourtype;
-  enum minimal_symbol_type ourtype2;
-  enum minimal_symbol_type ourtype3;
-  enum minimal_symbol_type ourtype4;
-  std::vector<symbol_search> result;
   gdb::optional<compiled_regex> preg;
   gdb::optional<compiled_regex> treg;
 
   gdb_assert (kind != ALL_DOMAIN);
 
-  ourtype = types[kind];
-  ourtype2 = types2[kind];
-  ourtype3 = types3[kind];
-  ourtype4 = types4[kind];
-
   if (regexp != NULL)
     {
       /* Make sure spacing is right for C++ operators.
@@ -4520,191 +4721,36 @@
       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, 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);
+      /* Expand symtabs within objfile that possibly contain matching
+	 symbols.  */
+      found_misc |= expand_symtabs (objfile, preg);
 
-		  QUIT;
-
-		  /* Check first sole REAL_SYMTAB->FILENAME.  It does
-		     not need to be a substring of symtab_to_fullname as
-		     it may contain "./" etc.  */
-		  if ((file_matches (real_symtab->filename, filenames, false)
-		       || ((basenames_may_differ
-			    || file_matches (lbasename (real_symtab->filename),
-					     filenames, true))
-			   && file_matches (symtab_to_fullname (real_symtab),
-					    filenames, false)))
-		      && ((!preg.has_value ()
-			   || preg->exec (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);
-		    }
-		}
-	    }
-	}
+      /* Find matching symbols within OBJFILE and add them in to
+	 RESULT_SET.  */
+      if (!add_matching_symbols (objfile, preg, treg, &result_set))
+	break;
     }
 
-  if (!result.empty ())
-    sort_search_symbols_remove_dups (&result);
+  /* 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 there are no eyes, avoid all contact.  I mean, if there are
-     no debug symbols, then add matching minsyms.  But if the user wants
-     to see symbols matching a type regexp, then never give a minimal symbol,
-     as we assume that a minimal symbol does not have a type.  */
-
-  if ((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 || (filenames.empty () && kind == VARIABLES_DOMAIN))
+      && !m_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 (!add_matching_msymbols (objfile, preg, &result))
+	  break;
     }
 
   return result;
diff --git a/gdb/symtab.h b/gdb/symtab.h
index c42dbdc..c265106 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -33,6 +33,8 @@
 #include "gdbsupport/next-iterator.h"
 #include "completer.h"
 
+#include <set>
+
 /* Opaque declarations.  */
 struct ui_file;
 struct frame_info;
@@ -2100,6 +2102,10 @@
      been constructed.  */
   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;
+
 private:
   /* The kind of symbols are we searching for.
      VARIABLES_DOMAIN - Search all symbols, excluding functions, type
@@ -2119,6 +2125,37 @@
   /* When this flag is false then minsyms that match M_SYMBOL_REGEXP will
      be included in the results, otherwise they are excluded.  */
   bool m_exclude_minsyms = false;
+
+  /* Expand symtabs in OBJFILE that match PREG, are of type M_KIND.  Return
+     true if any msymbols were seen that we should later consider adding to
+     the results list.  */
+  bool expand_symtabs (objfile *objfile,
+		       const gdb::optional<compiled_regex> &preg) const;
+
+  /* Add symbols from symtabs in OBJFILE that match PREG, and TREG, and are
+     of type M_KIND, 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), otherwise return true.  Returning
+     true does not indicate that any results were added, just that we
+     didn't _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
+  bool add_matching_symbols (objfile *objfile,
+			     const gdb::optional<compiled_regex> &preg,
+			     const gdb::optional<compiled_regex> &treg,
+			     std::set<symbol_search> *result_set) const;
+
+  /* Add msymbols from OBJFILE that match PREG and M_KIND, 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.  Returning true
+     does not indicate that any results were added, just that we didn't
+     _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
+  bool add_matching_msymbols (objfile *objfile,
+			      const gdb::optional<compiled_regex> &preg,
+			      std::vector<symbol_search> *results) const;
+
+  /* Return true if MSYMBOL is of type KIND.  */
+  static bool is_suitable_msymbol (const enum search_domain kind,
+				   const minimal_symbol *msymbol);
 };
 
 /* When searching for Fortran symbols within modules (functions/variables)
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 47445ea..8c6d304 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,9 @@
 2019-11-01  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* gdb.mi/mi-sym-info.exp: Add tests for -max-results parameter.
+
+2019-11-01  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* gdb.mi/mi-fortran-modules.exp: Add additional tests for
 	-symbol-info-module-functions and -symbol-info-module-variables.
 
diff --git a/gdb/testsuite/gdb.mi/mi-sym-info.exp b/gdb/testsuite/gdb.mi/mi-sym-info.exp
index 33fe865..80468a4 100644
--- a/gdb/testsuite/gdb.mi/mi-sym-info.exp
+++ b/gdb/testsuite/gdb.mi/mi-sym-info.exp
@@ -127,3 +127,28 @@
 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"
+
+
+
+

-- 
Gerrit-Project: binutils-gdb
Gerrit-Branch: master
Gerrit-Change-Id: I90a28feb55b388fb46461a096c5db08b6b0bd427
Gerrit-Change-Number: 269
Gerrit-PatchSet: 2
Gerrit-Owner: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-MessageType: newpatchset

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

* [review v3] gdb/mi: Add -max-results parameter to some -symbol-info-* commands
       [not found] <gerrit.1571909344000.I90a28feb55b388fb46461a096c5db08b6b0bd427@gnutoolchain-gerrit.osci.io>
  2019-11-01  1:35 ` [review v2] gdb/mi: Add -max-results parameter to some -symbol-info-* commands Andrew Burgess (Code Review)
@ 2019-11-08  0:50 ` Andrew Burgess (Code Review)
  2019-11-08 10:06   ` Eli Zaretskii
  2019-11-22 16:42 ` [review v4] " Andrew Burgess (Code Review)
                   ` (24 subsequent siblings)
  26 siblings, 1 reply; 28+ messages in thread
From: Andrew Burgess (Code Review) @ 2019-11-08  0:50 UTC (permalink / raw)
  To: gdb-patches

Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/269
......................................................................

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

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.
	(global_symbol_searcher::is_suitable_msymbol): New function.
	(global_symbol_searcher::expand_symtabs): New function.
	(global_symbol_searcher::add_matching_symbols): New function.
	(global_symbol_searcher::add_matching_msymbols): New function.
	(global_symbol_searcher::search_symbols): Move most of the content
	into the new functions above, and call them as needed.
	* symtab.h: Add 'set' include.
	(global_symbol_searcher) <max_search_results>: New member
	variable.
	(global_symbol_searcher) <expand_symtabs>: New member function.
	(global_symbol_searcher) <add_matching_symbols>: New member
	function.
	(global_symbol_searcher) <add_matching_msymbols>: New member
	function.
	(global_symbol_searcher) <is_suitable_msymbol>: New member
	function.

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
---
M gdb/ChangeLog
M gdb/doc/ChangeLog
M gdb/doc/gdb.texinfo
M gdb/mi/mi-symbol-cmds.c
M gdb/symtab.c
M gdb/symtab.h
M gdb/testsuite/ChangeLog
M gdb/testsuite/gdb.mi/mi-sym-info.exp
8 files changed, 424 insertions(+), 218 deletions(-)



diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index d3117a6..3c755db 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,32 @@
 2019-11-01  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* 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.
+	(global_symbol_searcher::is_suitable_msymbol): New function.
+	(global_symbol_searcher::expand_symtabs): New function.
+	(global_symbol_searcher::add_matching_symbols): New function.
+	(global_symbol_searcher::add_matching_msymbols): New function.
+	(global_symbol_searcher::search_symbols): Move most of the content
+	into the new functions above, and call them as needed.
+	* symtab.h: Add 'set' include.
+	(global_symbol_searcher) <max_search_results>: New member
+	variable.
+	(global_symbol_searcher) <expand_symtabs>: New member function.
+	(global_symbol_searcher) <add_matching_symbols>: New member
+	function.
+	(global_symbol_searcher) <add_matching_msymbols>: New member
+	function.
+	(global_symbol_searcher) <is_suitable_msymbol>: New member
+	function.
+
+2019-11-01  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* 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.
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 2901705..971bc94 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,5 +1,10 @@
 2019-11-01  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* doc/gdb.texinfo (GDB/MI Symbol Query): Add documentation of
+	-max-results to some -symbol-info-* commands.
+
+2019-11-01  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* doc/gdb.texinfo (GDB/MI Symbol Query): Document new MI command
 	-symbol-info-module-functions and -symbol-info-module-variables.
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 6219699..0f6d3b5 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -33864,6 +33864,7 @@
  -symbol-info-functions [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
 @end smallexample
 
 @noindent
@@ -33879,6 +33880,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}.
@@ -34110,6 +34116,8 @@
 
 @smallexample
  -symbol-info-modules [--name @var{name_regexp}]
+                      [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34120,6 +34128,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}.
@@ -34164,6 +34177,8 @@
 
 @smallexample
  -symbol-info-types [--name @var{name_regexp}]
+                    [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34177,6 +34192,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}.
@@ -34224,6 +34244,8 @@
  -symbol-info-variables [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34239,6 +34261,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 d211a8b..cfed30e 100644
--- a/gdb/mi/mi-symbol-cmds.c
+++ b/gdb/mi/mi-symbol-cmds.c
@@ -248,10 +248,12 @@
 
 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)
 {
   /* Must make sure that if we're interrupted, symbols gets freed.  */
   global_symbol_searcher sym_search (kind, regexp, t_regexp, exclude_minsyms);
+  sym_search.max_search_results = max_results;
   std::vector<symbol_search> symbols = sym_search.search ();
 
   mi_symbol_info_emitter emitter (current_uiout);
@@ -268,19 +270,21 @@
 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 }
   };
 
@@ -306,10 +310,19 @@
 	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.
@@ -443,15 +456,17 @@
 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 }
   };
 
@@ -469,10 +484,19 @@
 	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.  */
@@ -480,15 +504,17 @@
 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 }
   };
 
@@ -506,10 +532,19 @@
 	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 7608986..659ee97 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4359,8 +4359,8 @@
   return false;
 }
 
-/* Helper function for sort_search_symbols_remove_dups and qsort.  Can only
-   sort symbols, not minimal symbols.  */
+/* Helper function for std::sort on symbol_search objects.  Can only sort
+   symbols, not minimal symbols.  */
 
 int
 symbol_search::compare_search_syms (const symbol_search &sym_a,
@@ -4422,15 +4422,242 @@
   return treg.exec (printed_sym_type_name.c_str (), 0, NULL, 0) == 0;
 }
 
+/* See symtab.h.  */
 
-/* Sort the symbols in RESULT and remove duplicates.  */
-
-static void
-sort_search_symbols_remove_dups (std::vector<symbol_search> *result)
+bool
+global_symbol_searcher::is_suitable_msymbol
+	(const enum search_domain kind, const minimal_symbol *msymbol)
 {
-  std::sort (result->begin (), result->end ());
-  result->erase (std::unique (result->begin (), result->end ()),
-		 result->end ());
+  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};
+
+  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);
+}
+
+/* See symtab.h.  */
+
+bool
+global_symbol_searcher::expand_symtabs
+	(objfile *objfile, const gdb::optional<compiled_regex> &preg) const
+{
+  enum search_domain kind = m_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, 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 (filenames.empty ()
+      && (kind == VARIABLES_DOMAIN || kind == FUNCTIONS_DOMAIN))
+    {
+      for (minimal_symbol *msymbol : objfile->msymbols ())
+	{
+	  QUIT;
+
+	  if (msymbol->created_by_gdb)
+	    continue;
+
+	  if (is_suitable_msymbol (kind, msymbol))
+	    {
+	      if (!preg.has_value ()
+		  || preg->exec (MSYMBOL_NATURAL_NAME (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;
+}
+
+/* See symtab.h.  */
+bool
+global_symbol_searcher::add_matching_symbols
+	(objfile *objfile,
+	 const gdb::optional<compiled_regex> &preg,
+	 const gdb::optional<compiled_regex> &treg,
+	 std::set<symbol_search> *result_set) const
+{
+  enum search_domain kind = m_kind;
+
+  /* Add matching symbols (if not already present).  */
+  for (compunit_symtab *cust : objfile->compunits ())
+    {
+      const struct blockvector *bv  = COMPUNIT_BLOCKVECTOR (cust);
+
+      for (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, filenames, false)
+		   || ((basenames_may_differ
+			|| file_matches (lbasename (real_symtab->filename),
+					 filenames, true))
+		       && file_matches (symtab_to_fullname (real_symtab),
+					filenames, false)))
+		  && ((!preg.has_value ()
+		       || preg->exec (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 (max_search_results == -1
+		      || result_set->size () < 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;
+}
+
+/* See symtab.h.  */
+
+bool
+global_symbol_searcher::add_matching_msymbols
+	(objfile *objfile, const gdb::optional<compiled_regex> &preg,
+	 std::vector<symbol_search> *results) const
+{
+  enum search_domain kind = m_kind;
+
+  for (minimal_symbol *msymbol : objfile->msymbols ())
+    {
+      QUIT;
+
+      if (msymbol->created_by_gdb)
+	continue;
+
+      if (is_suitable_msymbol (kind, msymbol))
+	{
+	  if (!preg.has_value ()
+	      || preg->exec (MSYMBOL_NATURAL_NAME (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 (max_search_results == -1
+			  || (results->size () < max_search_results))
+			results->emplace_back (GLOBAL_BLOCK, msymbol, objfile);
+		      else
+			return false;
+		    }
+		}
+	    }
+	}
+    }
+
+  return true;
 }
 
 /* See symtab.h.  */
@@ -4441,37 +4668,11 @@
   const char *regexp = m_symbol_regexp;
   const char *t_regexp = m_type_regexp;
   enum search_domain kind = m_kind;
-  bool exclude_minsyms = m_exclude_minsyms;
-  int nfiles = filenames.size ();
-  const struct blockvector *bv;
-  const struct block *b;
-  int i = 0;
-  struct block_iterator iter;
-  struct symbol *sym;
-  int found_misc = 0;
-  static const enum minimal_symbol_type types[]
-    = {mst_data, mst_text, mst_unknown};
-  static const enum minimal_symbol_type types2[]
-    = {mst_bss, mst_file_text, mst_unknown};
-  static const enum minimal_symbol_type types3[]
-    = {mst_file_data, mst_solib_trampoline, mst_unknown};
-  static const enum minimal_symbol_type types4[]
-    = {mst_file_bss, mst_text_gnu_ifunc, mst_unknown};
-  enum minimal_symbol_type ourtype;
-  enum minimal_symbol_type ourtype2;
-  enum minimal_symbol_type ourtype3;
-  enum minimal_symbol_type ourtype4;
-  std::vector<symbol_search> result;
   gdb::optional<compiled_regex> preg;
   gdb::optional<compiled_regex> treg;
 
   gdb_assert (kind != ALL_DOMAIN);
 
-  ourtype = types[kind];
-  ourtype2 = types2[kind];
-  ourtype3 = types3[kind];
-  ourtype4 = types4[kind];
-
   if (regexp != NULL)
     {
       /* Make sure spacing is right for C++ operators.
@@ -4520,191 +4721,36 @@
       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, 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);
+      /* Expand symtabs within objfile that possibly contain matching
+	 symbols.  */
+      found_misc |= expand_symtabs (objfile, preg);
 
-		  QUIT;
-
-		  /* Check first sole REAL_SYMTAB->FILENAME.  It does
-		     not need to be a substring of symtab_to_fullname as
-		     it may contain "./" etc.  */
-		  if ((file_matches (real_symtab->filename, filenames, false)
-		       || ((basenames_may_differ
-			    || file_matches (lbasename (real_symtab->filename),
-					     filenames, true))
-			   && file_matches (symtab_to_fullname (real_symtab),
-					    filenames, false)))
-		      && ((!preg.has_value ()
-			   || preg->exec (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);
-		    }
-		}
-	    }
-	}
+      /* Find matching symbols within OBJFILE and add them in to
+	 RESULT_SET.  */
+      if (!add_matching_symbols (objfile, preg, treg, &result_set))
+	break;
     }
 
-  if (!result.empty ())
-    sort_search_symbols_remove_dups (&result);
+  /* 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 there are no eyes, avoid all contact.  I mean, if there are
-     no debug symbols, then add matching minsyms.  But if the user wants
-     to see symbols matching a type regexp, then never give a minimal symbol,
-     as we assume that a minimal symbol does not have a type.  */
-
-  if ((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 || (filenames.empty () && kind == VARIABLES_DOMAIN))
+      && !m_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 (!add_matching_msymbols (objfile, preg, &result))
+	  break;
     }
 
   return result;
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 62c964c..53e1dd3 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -33,6 +33,8 @@
 #include "gdbsupport/next-iterator.h"
 #include "completer.h"
 
+#include <set>
+
 /* Opaque declarations.  */
 struct ui_file;
 struct frame_info;
@@ -2111,6 +2113,10 @@
      been constructed.  */
   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;
+
 private:
   /* The kind of symbols are we searching for.
      VARIABLES_DOMAIN - Search all symbols, excluding functions, type
@@ -2130,6 +2136,37 @@
   /* When this flag is false then minsyms that match M_SYMBOL_REGEXP will
      be included in the results, otherwise they are excluded.  */
   bool m_exclude_minsyms = false;
+
+  /* Expand symtabs in OBJFILE that match PREG, are of type M_KIND.  Return
+     true if any msymbols were seen that we should later consider adding to
+     the results list.  */
+  bool expand_symtabs (objfile *objfile,
+		       const gdb::optional<compiled_regex> &preg) const;
+
+  /* Add symbols from symtabs in OBJFILE that match PREG, and TREG, and are
+     of type M_KIND, 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), otherwise return true.  Returning
+     true does not indicate that any results were added, just that we
+     didn't _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
+  bool add_matching_symbols (objfile *objfile,
+			     const gdb::optional<compiled_regex> &preg,
+			     const gdb::optional<compiled_regex> &treg,
+			     std::set<symbol_search> *result_set) const;
+
+  /* Add msymbols from OBJFILE that match PREG and M_KIND, 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.  Returning true
+     does not indicate that any results were added, just that we didn't
+     _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
+  bool add_matching_msymbols (objfile *objfile,
+			      const gdb::optional<compiled_regex> &preg,
+			      std::vector<symbol_search> *results) const;
+
+  /* Return true if MSYMBOL is of type KIND.  */
+  static bool is_suitable_msymbol (const enum search_domain kind,
+				   const minimal_symbol *msymbol);
 };
 
 /* When searching for Fortran symbols within modules (functions/variables)
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 1a19dac..b8f1cbc 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,9 @@
 2019-11-01  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* gdb.mi/mi-sym-info.exp: Add tests for -max-results parameter.
+
+2019-11-01  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* gdb.mi/mi-fortran-modules.exp: Add additional tests for
 	-symbol-info-module-functions and -symbol-info-module-variables.
 
diff --git a/gdb/testsuite/gdb.mi/mi-sym-info.exp b/gdb/testsuite/gdb.mi/mi-sym-info.exp
index 33fe865..80468a4 100644
--- a/gdb/testsuite/gdb.mi/mi-sym-info.exp
+++ b/gdb/testsuite/gdb.mi/mi-sym-info.exp
@@ -127,3 +127,28 @@
 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"
+
+
+
+

-- 
Gerrit-Project: binutils-gdb
Gerrit-Branch: master
Gerrit-Change-Id: I90a28feb55b388fb46461a096c5db08b6b0bd427
Gerrit-Change-Number: 269
Gerrit-PatchSet: 3
Gerrit-Owner: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-MessageType: newpatchset

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

* Re: [review v3] gdb/mi: Add -max-results parameter to some -symbol-info-* commands
  2019-11-08  0:50 ` [review v3] " Andrew Burgess (Code Review)
@ 2019-11-08 10:06   ` Eli Zaretskii
  0 siblings, 0 replies; 28+ messages in thread
From: Eli Zaretskii @ 2019-11-08 10:06 UTC (permalink / raw)
  To: andrew.burgess, gdb-patches

> Date: Thu, 7 Nov 2019 19:50:32 -0500
> From: "Andrew Burgess (Code Review)" <gerrit@gnutoolchain-gerrit.osci.io>
> 
> Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/269
> ......................................................................
> 
> gdb/mi: Add -max-results parameter to some -symbol-info-* commands
> 
> 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.
> 	(global_symbol_searcher::is_suitable_msymbol): New function.
> 	(global_symbol_searcher::expand_symtabs): New function.
> 	(global_symbol_searcher::add_matching_symbols): New function.
> 	(global_symbol_searcher::add_matching_msymbols): New function.
> 	(global_symbol_searcher::search_symbols): Move most of the content
> 	into the new functions above, and call them as needed.
> 	* symtab.h: Add 'set' include.
> 	(global_symbol_searcher) <max_search_results>: New member
> 	variable.
> 	(global_symbol_searcher) <expand_symtabs>: New member function.
> 	(global_symbol_searcher) <add_matching_symbols>: New member
> 	function.
> 	(global_symbol_searcher) <add_matching_msymbols>: New member
> 	function.
> 	(global_symbol_searcher) <is_suitable_msymbol>: New member
> 	function.
> 
> 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.

OK for the documentation part.

Thanks.

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

* [review v4] gdb/mi: Add -max-results parameter to some -symbol-info-* commands
       [not found] <gerrit.1571909344000.I90a28feb55b388fb46461a096c5db08b6b0bd427@gnutoolchain-gerrit.osci.io>
  2019-11-01  1:35 ` [review v2] gdb/mi: Add -max-results parameter to some -symbol-info-* commands Andrew Burgess (Code Review)
  2019-11-08  0:50 ` [review v3] " Andrew Burgess (Code Review)
@ 2019-11-22 16:42 ` Andrew Burgess (Code Review)
  2019-11-22 17:33 ` [review v5] " Andrew Burgess (Code Review)
                   ` (23 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrew Burgess (Code Review) @ 2019-11-22 16:42 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker

Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/269
......................................................................

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

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.
	(global_symbol_searcher::is_suitable_msymbol): New function.
	(global_symbol_searcher::expand_symtabs): New function.
	(global_symbol_searcher::add_matching_symbols): New function.
	(global_symbol_searcher::add_matching_msymbols): New function.
	(global_symbol_searcher::search_symbols): Move most of the content
	into the new functions above, and call them as needed.
	* symtab.h: Add 'set' include.
	(global_symbol_searcher) <set_max_seach_results>: New member
	function.
	(global_symbol_searcher) <m_max_search_results>: New member
	variable.
	(global_symbol_searcher) <expand_symtabs>: New member function.
	(global_symbol_searcher) <add_matching_symbols>: New member
	function.
	(global_symbol_searcher) <add_matching_msymbols>: New member
	function.
	(global_symbol_searcher) <is_suitable_msymbol>: New member
	function.

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
---
M gdb/ChangeLog
M gdb/doc/ChangeLog
M gdb/doc/gdb.texinfo
M gdb/mi/mi-symbol-cmds.c
M gdb/symtab.c
M gdb/symtab.h
M gdb/testsuite/ChangeLog
M gdb/testsuite/gdb.mi/mi-sym-info.exp
8 files changed, 431 insertions(+), 216 deletions(-)



diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index e67635f..ea41270 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,34 @@
 2019-11-22  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* 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.
+	(global_symbol_searcher::is_suitable_msymbol): New function.
+	(global_symbol_searcher::expand_symtabs): New function.
+	(global_symbol_searcher::add_matching_symbols): New function.
+	(global_symbol_searcher::add_matching_msymbols): New function.
+	(global_symbol_searcher::search_symbols): Move most of the content
+	into the new functions above, and call them as needed.
+	* symtab.h: Add 'set' include.
+	(global_symbol_searcher) <set_max_seach_results>: New member
+	function.
+	(global_symbol_searcher) <m_max_search_results>: New member
+	variable.
+	(global_symbol_searcher) <expand_symtabs>: New member function.
+	(global_symbol_searcher) <add_matching_symbols>: New member
+	function.
+	(global_symbol_searcher) <add_matching_msymbols>: New member
+	function.
+	(global_symbol_searcher) <is_suitable_msymbol>: New member
+	function.
+
+2019-11-22  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* 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.
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index ae310ea..36bde5a 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,5 +1,10 @@
 2019-11-22  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* doc/gdb.texinfo (GDB/MI Symbol Query): Add documentation of
+	-max-results to some -symbol-info-* commands.
+
+2019-11-22  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* doc/gdb.texinfo (GDB/MI Symbol Query): Document new MI command
 	-symbol-info-module-functions and -symbol-info-module-variables.
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index fb32528..e004ae3 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -33886,6 +33886,7 @@
  -symbol-info-functions [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
 @end smallexample
 
 @noindent
@@ -33901,6 +33902,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}.
@@ -34132,6 +34138,8 @@
 
 @smallexample
  -symbol-info-modules [--name @var{name_regexp}]
+                      [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34142,6 +34150,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}.
@@ -34186,6 +34199,8 @@
 
 @smallexample
  -symbol-info-types [--name @var{name_regexp}]
+                    [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34199,6 +34214,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}.
@@ -34246,6 +34266,8 @@
  -symbol-info-variables [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34261,6 +34283,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 7072d95..57bc103 100644
--- a/gdb/mi/mi-symbol-cmds.c
+++ b/gdb/mi/mi-symbol-cmds.c
@@ -248,12 +248,14 @@
 
 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)
 {
   /* Must make sure that if we're interrupted, symbols gets freed.  */
   global_symbol_searcher sym_search (kind, regexp);
   sym_search.set_symbol_type_regexp (t_regexp);
   sym_search.set_exclude_minsyms (exclude_minsyms);
+  sym_search.set_max_search_results (max_results);
   std::vector<symbol_search> symbols = sym_search.search ();
 
   mi_symbol_info_emitter emitter (current_uiout);
@@ -270,19 +272,21 @@
 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 }
   };
 
@@ -308,10 +312,19 @@
 	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.
@@ -445,15 +458,17 @@
 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 }
   };
 
@@ -471,10 +486,19 @@
 	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.  */
@@ -482,15 +506,17 @@
 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 }
   };
 
@@ -508,10 +534,19 @@
 	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 afdbfa7..19772b9 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4359,8 +4359,8 @@
   return false;
 }
 
-/* Helper function for sort_search_symbols_remove_dups and qsort.  Can only
-   sort symbols, not minimal symbols.  */
+/* Helper function for std::sort on symbol_search objects.  Can only sort
+   symbols, not minimal symbols.  */
 
 int
 symbol_search::compare_search_syms (const symbol_search &sym_a,
@@ -4422,15 +4422,242 @@
   return treg.exec (printed_sym_type_name.c_str (), 0, NULL, 0) == 0;
 }
 
+/* See symtab.h.  */
 
-/* Sort the symbols in RESULT and remove duplicates.  */
-
-static void
-sort_search_symbols_remove_dups (std::vector<symbol_search> *result)
+bool
+global_symbol_searcher::is_suitable_msymbol
+	(const enum search_domain kind, const minimal_symbol *msymbol)
 {
-  std::sort (result->begin (), result->end ());
-  result->erase (std::unique (result->begin (), result->end ()),
-		 result->end ());
+  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};
+
+  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);
+}
+
+/* See symtab.h.  */
+
+bool
+global_symbol_searcher::expand_symtabs
+	(objfile *objfile, const gdb::optional<compiled_regex> &preg) const
+{
+  enum search_domain kind = m_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, 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 (filenames.empty ()
+      && (kind == VARIABLES_DOMAIN || kind == FUNCTIONS_DOMAIN))
+    {
+      for (minimal_symbol *msymbol : objfile->msymbols ())
+	{
+	  QUIT;
+
+	  if (msymbol->created_by_gdb)
+	    continue;
+
+	  if (is_suitable_msymbol (kind, msymbol))
+	    {
+	      if (!preg.has_value ()
+		  || preg->exec (MSYMBOL_NATURAL_NAME (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;
+}
+
+/* See symtab.h.  */
+bool
+global_symbol_searcher::add_matching_symbols
+	(objfile *objfile,
+	 const gdb::optional<compiled_regex> &preg,
+	 const gdb::optional<compiled_regex> &treg,
+	 std::set<symbol_search> *result_set) const
+{
+  enum search_domain kind = m_kind;
+
+  /* Add matching symbols (if not already present).  */
+  for (compunit_symtab *cust : objfile->compunits ())
+    {
+      const struct blockvector *bv  = COMPUNIT_BLOCKVECTOR (cust);
+
+      for (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, filenames, false)
+		   || ((basenames_may_differ
+			|| file_matches (lbasename (real_symtab->filename),
+					 filenames, true))
+		       && file_matches (symtab_to_fullname (real_symtab),
+					filenames, false)))
+		  && ((!preg.has_value ()
+		       || preg->exec (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 (m_max_search_results == -1
+		      || result_set->size () < m_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;
+}
+
+/* See symtab.h.  */
+
+bool
+global_symbol_searcher::add_matching_msymbols
+	(objfile *objfile, const gdb::optional<compiled_regex> &preg,
+	 std::vector<symbol_search> *results) const
+{
+  enum search_domain kind = m_kind;
+
+  for (minimal_symbol *msymbol : objfile->msymbols ())
+    {
+      QUIT;
+
+      if (msymbol->created_by_gdb)
+	continue;
+
+      if (is_suitable_msymbol (kind, msymbol))
+	{
+	  if (!preg.has_value ()
+	      || preg->exec (MSYMBOL_NATURAL_NAME (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 (m_max_search_results == -1
+			  || (results->size () < m_max_search_results))
+			results->emplace_back (GLOBAL_BLOCK, msymbol, objfile);
+		      else
+			return false;
+		    }
+		}
+	    }
+	}
+    }
+
+  return true;
 }
 
 /* See symtab.h.  */
@@ -4438,35 +4665,11 @@
 std::vector<symbol_search>
 global_symbol_searcher::search () const
 {
-  const struct blockvector *bv;
-  const struct block *b;
-  int i = 0;
-  struct block_iterator iter;
-  struct symbol *sym;
-  int found_misc = 0;
-  static const enum minimal_symbol_type types[]
-    = {mst_data, mst_text, mst_unknown};
-  static const enum minimal_symbol_type types2[]
-    = {mst_bss, mst_file_text, mst_unknown};
-  static const enum minimal_symbol_type types3[]
-    = {mst_file_data, mst_solib_trampoline, mst_unknown};
-  static const enum minimal_symbol_type types4[]
-    = {mst_file_bss, mst_text_gnu_ifunc, mst_unknown};
-  enum minimal_symbol_type ourtype;
-  enum minimal_symbol_type ourtype2;
-  enum minimal_symbol_type ourtype3;
-  enum minimal_symbol_type ourtype4;
-  std::vector<symbol_search> result;
   gdb::optional<compiled_regex> preg;
   gdb::optional<compiled_regex> treg;
 
   gdb_assert (m_kind != ALL_DOMAIN);
 
-  ourtype = types[m_kind];
-  ourtype2 = types2[m_kind];
-  ourtype3 = types3[m_kind];
-  ourtype4 = types4[m_kind];
-
   if (m_symbol_name_regexp != NULL)
     {
       const char *symbol_name_regexp = m_symbol_name_regexp;
@@ -4519,192 +4722,36 @@
 		    _("Invalid m_symbol_namregexp"));
     }
 
-  /* Search through the partial symtabs *first* for all symbols
-     matching the m_symbol_namregexp.  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, filenames,
-						  basenames) ? 1 : 0;
-			   },
-			   lookup_name_info::match_any (),
-			   [&] (const char *symname)
-			   {
-			     return (!preg.has_value ()
-				     || preg->exec (symname,
-						    0, NULL, 0) == 0);
-			   },
-			   NULL,
-			   m_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 (filenames.empty () && (m_kind == VARIABLES_DOMAIN
-			     || m_kind == FUNCTIONS_DOMAIN))
-    {
-      for (objfile *objfile : current_program_space->objfiles ())
-	{
-	  for (minimal_symbol *msymbol : objfile->msymbols ())
-	    {
-	      QUIT;
-
-	      if (msymbol->created_by_gdb)
-		continue;
-
-	      if (MSYMBOL_TYPE (msymbol) == ourtype
-		  || MSYMBOL_TYPE (msymbol) == ourtype2
-		  || MSYMBOL_TYPE (msymbol) == ourtype3
-		  || MSYMBOL_TYPE (msymbol) == ourtype4)
-		{
-		  if (!preg.has_value ()
-		      || preg->exec (MSYMBOL_NATURAL_NAME (msymbol), 0,
-				     NULL, 0) == 0)
-		    {
-		      /* 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 (m_kind == FUNCTIONS_DOMAIN
-			  ? (find_pc_compunit_symtab
-			     (MSYMBOL_VALUE_ADDRESS (objfile, msymbol))
-			     == NULL)
-			  : (lookup_symbol_in_objfile_from_linkage_name
-			     (objfile, MSYMBOL_LINKAGE_NAME (msymbol),
-			      VAR_DOMAIN)
-			     .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);
+      /* Expand symtabs within objfile that possibly contain matching
+	 symbols.  */
+      found_misc |= expand_symtabs (objfile, preg);
 
-		  QUIT;
-
-		  /* Check first sole REAL_SYMTAB->FILENAME.  It does
-		     not need to be a substring of symtab_to_fullname as
-		     it may contain "./" etc.  */
-		  if ((file_matches (real_symtab->filename, filenames, false)
-		       || ((basenames_may_differ
-			    || file_matches (lbasename (real_symtab->filename),
-					     filenames, true))
-			   && file_matches (symtab_to_fullname (real_symtab),
-					    filenames, false)))
-		      && ((!preg.has_value ()
-			   || preg->exec (SYMBOL_NATURAL_NAME (sym), 0,
-					  NULL, 0) == 0)
-			  && ((m_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)))
-			      || (m_kind == FUNCTIONS_DOMAIN
-				  && SYMBOL_CLASS (sym) == LOC_BLOCK
-				  && (!treg.has_value ()
-				      || treg_matches_sym_type_name (*treg,
-								     sym)))
-			      || (m_kind == TYPES_DOMAIN
-				  && SYMBOL_CLASS (sym) == LOC_TYPEDEF
-				  && SYMBOL_DOMAIN (sym) != MODULE_DOMAIN)
-			      || (m_kind == MODULES_DOMAIN
-				  && SYMBOL_DOMAIN (sym) == MODULE_DOMAIN
-				  && SYMBOL_LINE (sym) != 0))))
-		    {
-		      /* match */
-		      result.emplace_back (i, sym);
-		    }
-		}
-	    }
-	}
+      /* Find matching symbols within OBJFILE and add them in to
+	 RESULT_SET.  */
+      if (!add_matching_symbols (objfile, preg, treg, &result_set))
+	break;
     }
 
-  if (!result.empty ())
-    sort_search_symbols_remove_dups (&result);
+  /* 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 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 m_symbol_namregexp, then never give a minimal symbol,
-     as we assume that a minimal symbol does not have a type.  */
-
-  if ((found_misc || (filenames.empty () && m_kind != FUNCTIONS_DOMAIN))
+  /* 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 || (filenames.empty () && m_kind == VARIABLES_DOMAIN))
       && !m_exclude_minsyms
       && !treg.has_value ())
     {
+      gdb_assert (m_kind == VARIABLES_DOMAIN || m_kind == FUNCTIONS_DOMAIN);
       for (objfile *objfile : current_program_space->objfiles ())
-	{
-	  for (minimal_symbol *msymbol : objfile->msymbols ())
-	    {
-	      QUIT;
-
-	      if (msymbol->created_by_gdb)
-		continue;
-
-	      if (MSYMBOL_TYPE (msymbol) == ourtype
-		  || MSYMBOL_TYPE (msymbol) == ourtype2
-		  || MSYMBOL_TYPE (msymbol) == ourtype3
-		  || MSYMBOL_TYPE (msymbol) == ourtype4)
-		{
-		  if (!preg.has_value ()
-		      || preg->exec (MSYMBOL_NATURAL_NAME (msymbol), 0,
-				     NULL, 0) == 0)
-		    {
-		      /* For functions we can do a quick check of whether the
-			 symbol might be found via find_pc_symtab.  */
-		      if (m_kind != FUNCTIONS_DOMAIN
-			  || (find_pc_compunit_symtab
-			      (MSYMBOL_VALUE_ADDRESS (objfile, msymbol))
-			      == NULL))
-			{
-			  if (lookup_symbol_in_objfile_from_linkage_name
-			      (objfile, MSYMBOL_LINKAGE_NAME (msymbol),
-			       VAR_DOMAIN)
-			      .symbol == NULL)
-			    {
-			      /* match */
-			      result.emplace_back (i, msymbol, objfile);
-			    }
-			}
-		    }
-		}
-	    }
-	}
+	if (!add_matching_msymbols (objfile, preg, &result))
+	  break;
     }
 
   return result;
diff --git a/gdb/symtab.h b/gdb/symtab.h
index d4dbc2c..aa30f39 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -35,6 +35,8 @@
 #include "completer.h"
 #include "gdb-demangle.h"
 
+#include <set>
+
 /* Opaque declarations.  */
 struct ui_file;
 struct frame_info;
@@ -2106,6 +2108,12 @@
     m_exclude_minsyms = exclude_minsyms;
   }
 
+  /* Set the maximum number of search results to be returned.  */
+  void set_max_search_results (int max_search_results)
+  {
+    m_max_search_results = max_search_results;
+  }
+
   /* Search the symbols from all objfiles in the current program space
      looking for matches as defined by the current state of this object.
 
@@ -2138,6 +2146,41 @@
   /* When this flag is false then minsyms that match M_SYMBOL_REGEXP will
      be included in the results, otherwise they are excluded.  */
   bool m_exclude_minsyms = false;
+
+  /* Maximum number of search results, set to -1 for unlimited, otherwise
+     set to a positive value to limit the number of results returned.  */
+  int m_max_search_results = -1;
+
+  /* Expand symtabs in OBJFILE that match PREG, are of type M_KIND.  Return
+     true if any msymbols were seen that we should later consider adding to
+     the results list.  */
+  bool expand_symtabs (objfile *objfile,
+		       const gdb::optional<compiled_regex> &preg) const;
+
+  /* Add symbols from symtabs in OBJFILE that match PREG, and TREG, and are
+     of type M_KIND, 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), otherwise return true.  Returning
+     true does not indicate that any results were added, just that we
+     didn't _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
+  bool add_matching_symbols (objfile *objfile,
+			     const gdb::optional<compiled_regex> &preg,
+			     const gdb::optional<compiled_regex> &treg,
+			     std::set<symbol_search> *result_set) const;
+
+  /* Add msymbols from OBJFILE that match PREG and M_KIND, 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.  Returning true
+     does not indicate that any results were added, just that we didn't
+     _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
+  bool add_matching_msymbols (objfile *objfile,
+			      const gdb::optional<compiled_regex> &preg,
+			      std::vector<symbol_search> *results) const;
+
+  /* Return true if MSYMBOL is of type KIND.  */
+  static bool is_suitable_msymbol (const enum search_domain kind,
+				   const minimal_symbol *msymbol);
 };
 
 /* When searching for Fortran symbols within modules (functions/variables)
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 518d9cb..6807104 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,9 @@
 2019-11-22  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* gdb.mi/mi-sym-info.exp: Add tests for -max-results parameter.
+
+2019-11-22  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* gdb.mi/mi-fortran-modules.exp: Add additional tests for
 	-symbol-info-module-functions and -symbol-info-module-variables.
 
diff --git a/gdb/testsuite/gdb.mi/mi-sym-info.exp b/gdb/testsuite/gdb.mi/mi-sym-info.exp
index 33fe865..80468a4 100644
--- a/gdb/testsuite/gdb.mi/mi-sym-info.exp
+++ b/gdb/testsuite/gdb.mi/mi-sym-info.exp
@@ -127,3 +127,28 @@
 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"
+
+
+
+

-- 
Gerrit-Project: binutils-gdb
Gerrit-Branch: master
Gerrit-Change-Id: I90a28feb55b388fb46461a096c5db08b6b0bd427
Gerrit-Change-Number: 269
Gerrit-PatchSet: 4
Gerrit-Owner: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-CC: Joel Brobecker <brobecker@adacore.com>
Gerrit-MessageType: newpatchset

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

* [review v5] gdb/mi: Add -max-results parameter to some -symbol-info-* commands
       [not found] <gerrit.1571909344000.I90a28feb55b388fb46461a096c5db08b6b0bd427@gnutoolchain-gerrit.osci.io>
                   ` (2 preceding siblings ...)
  2019-11-22 16:42 ` [review v4] " Andrew Burgess (Code Review)
@ 2019-11-22 17:33 ` Andrew Burgess (Code Review)
  2019-11-26 23:26 ` [review v6] " Andrew Burgess (Code Review)
                   ` (22 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrew Burgess (Code Review) @ 2019-11-22 17:33 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker

Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/269
......................................................................

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

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.
	(global_symbol_searcher::is_suitable_msymbol): New function.
	(global_symbol_searcher::expand_symtabs): New function.
	(global_symbol_searcher::add_matching_symbols): New function.
	(global_symbol_searcher::add_matching_msymbols): New function.
	(global_symbol_searcher::search_symbols): Move most of the content
	into the new functions above, and call them as needed.
	* symtab.h: Add 'set' include.
	(global_symbol_searcher) <set_max_seach_results>: New member
	function.
	(global_symbol_searcher) <m_max_search_results>: New member
	variable.
	(global_symbol_searcher) <expand_symtabs>: New member function.
	(global_symbol_searcher) <add_matching_symbols>: New member
	function.
	(global_symbol_searcher) <add_matching_msymbols>: New member
	function.
	(global_symbol_searcher) <is_suitable_msymbol>: New member
	function.

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
---
M gdb/ChangeLog
M gdb/doc/ChangeLog
M gdb/doc/gdb.texinfo
M gdb/mi/mi-symbol-cmds.c
M gdb/symtab.c
M gdb/symtab.h
M gdb/testsuite/ChangeLog
M gdb/testsuite/gdb.mi/mi-sym-info.exp
8 files changed, 428 insertions(+), 213 deletions(-)



diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index e67635f..ea41270 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,34 @@
 2019-11-22  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* 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.
+	(global_symbol_searcher::is_suitable_msymbol): New function.
+	(global_symbol_searcher::expand_symtabs): New function.
+	(global_symbol_searcher::add_matching_symbols): New function.
+	(global_symbol_searcher::add_matching_msymbols): New function.
+	(global_symbol_searcher::search_symbols): Move most of the content
+	into the new functions above, and call them as needed.
+	* symtab.h: Add 'set' include.
+	(global_symbol_searcher) <set_max_seach_results>: New member
+	function.
+	(global_symbol_searcher) <m_max_search_results>: New member
+	variable.
+	(global_symbol_searcher) <expand_symtabs>: New member function.
+	(global_symbol_searcher) <add_matching_symbols>: New member
+	function.
+	(global_symbol_searcher) <add_matching_msymbols>: New member
+	function.
+	(global_symbol_searcher) <is_suitable_msymbol>: New member
+	function.
+
+2019-11-22  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* 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.
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index ae310ea..36bde5a 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,5 +1,10 @@
 2019-11-22  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* doc/gdb.texinfo (GDB/MI Symbol Query): Add documentation of
+	-max-results to some -symbol-info-* commands.
+
+2019-11-22  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* doc/gdb.texinfo (GDB/MI Symbol Query): Document new MI command
 	-symbol-info-module-functions and -symbol-info-module-variables.
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index fb32528..e004ae3 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -33886,6 +33886,7 @@
  -symbol-info-functions [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
 @end smallexample
 
 @noindent
@@ -33901,6 +33902,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}.
@@ -34132,6 +34138,8 @@
 
 @smallexample
  -symbol-info-modules [--name @var{name_regexp}]
+                      [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34142,6 +34150,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}.
@@ -34186,6 +34199,8 @@
 
 @smallexample
  -symbol-info-types [--name @var{name_regexp}]
+                    [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34199,6 +34214,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}.
@@ -34246,6 +34266,8 @@
  -symbol-info-variables [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34261,6 +34283,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 de6d86d..1b31fc4 100644
--- a/gdb/mi/mi-symbol-cmds.c
+++ b/gdb/mi/mi-symbol-cmds.c
@@ -248,11 +248,13 @@
 
 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)
 {
   global_symbol_searcher sym_search (kind, regexp);
   sym_search.set_symbol_type_regexp (t_regexp);
   sym_search.set_exclude_minsyms (exclude_minsyms);
+  sym_search.set_max_search_results (max_results);
   std::vector<symbol_search> symbols = sym_search.search ();
 
   mi_symbol_info_emitter emitter (current_uiout);
@@ -269,19 +271,21 @@
 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 }
   };
 
@@ -307,10 +311,19 @@
 	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.
@@ -444,15 +457,17 @@
 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 }
   };
 
@@ -470,10 +485,19 @@
 	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.  */
@@ -481,15 +505,17 @@
 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 }
   };
 
@@ -507,10 +533,19 @@
 	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 eb6a995..6394f09 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4359,8 +4359,8 @@
   return false;
 }
 
-/* Helper function for sort_search_symbols_remove_dups and qsort.  Can only
-   sort symbols, not minimal symbols.  */
+/* Helper function for std::sort on symbol_search objects.  Can only sort
+   symbols, not minimal symbols.  */
 
 int
 symbol_search::compare_search_syms (const symbol_search &sym_a,
@@ -4422,15 +4422,239 @@
   return treg.exec (printed_sym_type_name.c_str (), 0, NULL, 0) == 0;
 }
 
+/* See symtab.h.  */
 
-/* Sort the symbols in RESULT and remove duplicates.  */
-
-static void
-sort_search_symbols_remove_dups (std::vector<symbol_search> *result)
+bool
+global_symbol_searcher::is_suitable_msymbol
+	(const enum search_domain kind, const minimal_symbol *msymbol)
 {
-  std::sort (result->begin (), result->end ());
-  result->erase (std::unique (result->begin (), result->end ()),
-		 result->end ());
+  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};
+
+  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);
+}
+
+/* See symtab.h.  */
+
+bool
+global_symbol_searcher::expand_symtabs
+	(objfile *objfile, const gdb::optional<compiled_regex> &preg) const
+{
+  enum search_domain kind = m_kind;
+  bool found_misc = false;
+
+  if (objfile->sf)
+    objfile->sf->qf->expand_symtabs_matching
+      (objfile,
+       [&] (const char *filename, bool basenames)
+       {
+	 return file_matches (filename, filenames, basenames);
+       },
+       lookup_name_info::match_any (),
+       [&] (const char *symname)
+       {
+	 return (!preg.has_value ()
+		 || preg->exec (symname, 0, NULL, 0) == 0);
+       },
+       NULL,
+       kind);
+
+  /* Here, we search through the minimal symbol tables for functions and
+     variables that match, and force their symbols to be read.  This is in
+     particular necessary for demangled variable names, which are no longer
+     put into the partial symbol tables.  The symbol will then be found
+     during the scan of symtabs later.
+
+     For functions, find_pc_symtab should succeed if we have debug info for
+     the function, for variables we have to call
+     lookup_symbol_in_objfile_from_linkage_name to determine if the
+     variable has debug info.  If the lookup fails, set found_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 (filenames.empty ()
+      && (kind == VARIABLES_DOMAIN || kind == FUNCTIONS_DOMAIN))
+    {
+      for (minimal_symbol *msymbol : objfile->msymbols ())
+	{
+	  QUIT;
+
+	  if (msymbol->created_by_gdb)
+	    continue;
+
+	  if (is_suitable_msymbol (kind, msymbol))
+	    {
+	      if (!preg.has_value ()
+		  || preg->exec (MSYMBOL_NATURAL_NAME (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;
+}
+
+/* See symtab.h.  */
+bool
+global_symbol_searcher::add_matching_symbols
+	(objfile *objfile,
+	 const gdb::optional<compiled_regex> &preg,
+	 const gdb::optional<compiled_regex> &treg,
+	 std::set<symbol_search> *result_set) const
+{
+  enum search_domain kind = m_kind;
+
+  /* Add matching symbols (if not already present).  */
+  for (compunit_symtab *cust : objfile->compunits ())
+    {
+      const struct blockvector *bv  = COMPUNIT_BLOCKVECTOR (cust);
+
+      for (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, filenames, false)
+		   || ((basenames_may_differ
+			|| file_matches (lbasename (real_symtab->filename),
+					 filenames, true))
+		       && file_matches (symtab_to_fullname (real_symtab),
+					filenames, false)))
+		  && ((!preg.has_value ()
+		       || preg->exec (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 (m_max_search_results == -1
+		      || result_set->size () < m_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;
+}
+
+/* See symtab.h.  */
+
+bool
+global_symbol_searcher::add_matching_msymbols
+	(objfile *objfile, const gdb::optional<compiled_regex> &preg,
+	 std::vector<symbol_search> *results) const
+{
+  enum search_domain kind = m_kind;
+
+  for (minimal_symbol *msymbol : objfile->msymbols ())
+    {
+      QUIT;
+
+      if (msymbol->created_by_gdb)
+	continue;
+
+      if (is_suitable_msymbol (kind, msymbol))
+	{
+	  if (!preg.has_value ()
+	      || preg->exec (MSYMBOL_NATURAL_NAME (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 (m_max_search_results == -1
+			  || (results->size () < m_max_search_results))
+			results->emplace_back (GLOBAL_BLOCK, msymbol, objfile);
+		      else
+			return false;
+		    }
+		}
+	    }
+	}
+    }
+
+  return true;
 }
 
 /* See symtab.h.  */
@@ -4438,35 +4662,11 @@
 std::vector<symbol_search>
 global_symbol_searcher::search () const
 {
-  const struct blockvector *bv;
-  const struct block *b;
-  int i = 0;
-  struct block_iterator iter;
-  struct symbol *sym;
-  int found_misc = 0;
-  static const enum minimal_symbol_type types[]
-    = {mst_data, mst_text, mst_unknown};
-  static const enum minimal_symbol_type types2[]
-    = {mst_bss, mst_file_text, mst_unknown};
-  static const enum minimal_symbol_type types3[]
-    = {mst_file_data, mst_solib_trampoline, mst_unknown};
-  static const enum minimal_symbol_type types4[]
-    = {mst_file_bss, mst_text_gnu_ifunc, mst_unknown};
-  enum minimal_symbol_type ourtype;
-  enum minimal_symbol_type ourtype2;
-  enum minimal_symbol_type ourtype3;
-  enum minimal_symbol_type ourtype4;
-  std::vector<symbol_search> result;
   gdb::optional<compiled_regex> preg;
   gdb::optional<compiled_regex> treg;
 
   gdb_assert (m_kind != ALL_DOMAIN);
 
-  ourtype = types[m_kind];
-  ourtype2 = types2[m_kind];
-  ourtype3 = types3[m_kind];
-  ourtype4 = types4[m_kind];
-
   if (m_symbol_name_regexp != NULL)
     {
       const char *symbol_name_regexp = m_symbol_name_regexp;
@@ -4519,189 +4719,36 @@
 		    _("Invalid m_symbol_namregexp"));
     }
 
-  /* Search through the partial symtabs *first* for all symbols
-     matching the m_symbol_namregexp.  That way we don't have to reproduce all of
-     the machinery below.  */
-  expand_symtabs_matching ([&] (const char *filename, bool basenames)
-			   {
-			     return file_matches (filename, filenames,
-						  basenames);
-			   },
-			   lookup_name_info::match_any (),
-			   [&] (const char *symname)
-			   {
-			     return (!preg.has_value ()
-				     || preg->exec (symname,
-						    0, NULL, 0) == 0);
-			   },
-			   NULL,
-			   m_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 (filenames.empty () && (m_kind == VARIABLES_DOMAIN
-			     || m_kind == FUNCTIONS_DOMAIN))
-    {
-      for (objfile *objfile : current_program_space->objfiles ())
-	{
-	  for (minimal_symbol *msymbol : objfile->msymbols ())
-	    {
-	      QUIT;
-
-	      if (msymbol->created_by_gdb)
-		continue;
-
-	      if (MSYMBOL_TYPE (msymbol) == ourtype
-		  || MSYMBOL_TYPE (msymbol) == ourtype2
-		  || MSYMBOL_TYPE (msymbol) == ourtype3
-		  || MSYMBOL_TYPE (msymbol) == ourtype4)
-		{
-		  if (!preg.has_value ()
-		      || preg->exec (MSYMBOL_NATURAL_NAME (msymbol), 0,
-				     NULL, 0) == 0)
-		    {
-		      /* 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 (m_kind == FUNCTIONS_DOMAIN
-			  ? (find_pc_compunit_symtab
-			     (MSYMBOL_VALUE_ADDRESS (objfile, msymbol))
-			     == NULL)
-			  : (lookup_symbol_in_objfile_from_linkage_name
-			     (objfile, MSYMBOL_LINKAGE_NAME (msymbol),
-			      VAR_DOMAIN)
-			     .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);
+      /* Expand symtabs within objfile that possibly contain matching
+	 symbols.  */
+      found_misc |= expand_symtabs (objfile, preg);
 
-		  QUIT;
-
-		  /* Check first sole REAL_SYMTAB->FILENAME.  It does
-		     not need to be a substring of symtab_to_fullname as
-		     it may contain "./" etc.  */
-		  if ((file_matches (real_symtab->filename, filenames, false)
-		       || ((basenames_may_differ
-			    || file_matches (lbasename (real_symtab->filename),
-					     filenames, true))
-			   && file_matches (symtab_to_fullname (real_symtab),
-					    filenames, false)))
-		      && ((!preg.has_value ()
-			   || preg->exec (SYMBOL_NATURAL_NAME (sym), 0,
-					  NULL, 0) == 0)
-			  && ((m_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)))
-			      || (m_kind == FUNCTIONS_DOMAIN
-				  && SYMBOL_CLASS (sym) == LOC_BLOCK
-				  && (!treg.has_value ()
-				      || treg_matches_sym_type_name (*treg,
-								     sym)))
-			      || (m_kind == TYPES_DOMAIN
-				  && SYMBOL_CLASS (sym) == LOC_TYPEDEF
-				  && SYMBOL_DOMAIN (sym) != MODULE_DOMAIN)
-			      || (m_kind == MODULES_DOMAIN
-				  && SYMBOL_DOMAIN (sym) == MODULE_DOMAIN
-				  && SYMBOL_LINE (sym) != 0))))
-		    {
-		      /* match */
-		      result.emplace_back (i, sym);
-		    }
-		}
-	    }
-	}
+      /* Find matching symbols within OBJFILE and add them in to
+	 RESULT_SET.  */
+      if (!add_matching_symbols (objfile, preg, treg, &result_set))
+	break;
     }
 
-  if (!result.empty ())
-    sort_search_symbols_remove_dups (&result);
+  /* 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 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 m_symbol_namregexp, then never give a minimal symbol,
-     as we assume that a minimal symbol does not have a type.  */
-
-  if ((found_misc || (filenames.empty () && m_kind != FUNCTIONS_DOMAIN))
+  /* 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 || (filenames.empty () && m_kind == VARIABLES_DOMAIN))
       && !m_exclude_minsyms
       && !treg.has_value ())
     {
+      gdb_assert (m_kind == VARIABLES_DOMAIN || m_kind == FUNCTIONS_DOMAIN);
       for (objfile *objfile : current_program_space->objfiles ())
-	{
-	  for (minimal_symbol *msymbol : objfile->msymbols ())
-	    {
-	      QUIT;
-
-	      if (msymbol->created_by_gdb)
-		continue;
-
-	      if (MSYMBOL_TYPE (msymbol) == ourtype
-		  || MSYMBOL_TYPE (msymbol) == ourtype2
-		  || MSYMBOL_TYPE (msymbol) == ourtype3
-		  || MSYMBOL_TYPE (msymbol) == ourtype4)
-		{
-		  if (!preg.has_value ()
-		      || preg->exec (MSYMBOL_NATURAL_NAME (msymbol), 0,
-				     NULL, 0) == 0)
-		    {
-		      /* For functions we can do a quick check of whether the
-			 symbol might be found via find_pc_symtab.  */
-		      if (m_kind != FUNCTIONS_DOMAIN
-			  || (find_pc_compunit_symtab
-			      (MSYMBOL_VALUE_ADDRESS (objfile, msymbol))
-			      == NULL))
-			{
-			  if (lookup_symbol_in_objfile_from_linkage_name
-			      (objfile, MSYMBOL_LINKAGE_NAME (msymbol),
-			       VAR_DOMAIN)
-			      .symbol == NULL)
-			    {
-			      /* match */
-			      result.emplace_back (i, msymbol, objfile);
-			    }
-			}
-		    }
-		}
-	    }
-	}
+	if (!add_matching_msymbols (objfile, preg, &result))
+	  break;
     }
 
   return result;
diff --git a/gdb/symtab.h b/gdb/symtab.h
index d4dbc2c..aa30f39 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -35,6 +35,8 @@
 #include "completer.h"
 #include "gdb-demangle.h"
 
+#include <set>
+
 /* Opaque declarations.  */
 struct ui_file;
 struct frame_info;
@@ -2106,6 +2108,12 @@
     m_exclude_minsyms = exclude_minsyms;
   }
 
+  /* Set the maximum number of search results to be returned.  */
+  void set_max_search_results (int max_search_results)
+  {
+    m_max_search_results = max_search_results;
+  }
+
   /* Search the symbols from all objfiles in the current program space
      looking for matches as defined by the current state of this object.
 
@@ -2138,6 +2146,41 @@
   /* When this flag is false then minsyms that match M_SYMBOL_REGEXP will
      be included in the results, otherwise they are excluded.  */
   bool m_exclude_minsyms = false;
+
+  /* Maximum number of search results, set to -1 for unlimited, otherwise
+     set to a positive value to limit the number of results returned.  */
+  int m_max_search_results = -1;
+
+  /* Expand symtabs in OBJFILE that match PREG, are of type M_KIND.  Return
+     true if any msymbols were seen that we should later consider adding to
+     the results list.  */
+  bool expand_symtabs (objfile *objfile,
+		       const gdb::optional<compiled_regex> &preg) const;
+
+  /* Add symbols from symtabs in OBJFILE that match PREG, and TREG, and are
+     of type M_KIND, 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), otherwise return true.  Returning
+     true does not indicate that any results were added, just that we
+     didn't _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
+  bool add_matching_symbols (objfile *objfile,
+			     const gdb::optional<compiled_regex> &preg,
+			     const gdb::optional<compiled_regex> &treg,
+			     std::set<symbol_search> *result_set) const;
+
+  /* Add msymbols from OBJFILE that match PREG and M_KIND, 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.  Returning true
+     does not indicate that any results were added, just that we didn't
+     _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
+  bool add_matching_msymbols (objfile *objfile,
+			      const gdb::optional<compiled_regex> &preg,
+			      std::vector<symbol_search> *results) const;
+
+  /* Return true if MSYMBOL is of type KIND.  */
+  static bool is_suitable_msymbol (const enum search_domain kind,
+				   const minimal_symbol *msymbol);
 };
 
 /* When searching for Fortran symbols within modules (functions/variables)
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 518d9cb..6807104 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,9 @@
 2019-11-22  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* gdb.mi/mi-sym-info.exp: Add tests for -max-results parameter.
+
+2019-11-22  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* gdb.mi/mi-fortran-modules.exp: Add additional tests for
 	-symbol-info-module-functions and -symbol-info-module-variables.
 
diff --git a/gdb/testsuite/gdb.mi/mi-sym-info.exp b/gdb/testsuite/gdb.mi/mi-sym-info.exp
index 33fe865..80468a4 100644
--- a/gdb/testsuite/gdb.mi/mi-sym-info.exp
+++ b/gdb/testsuite/gdb.mi/mi-sym-info.exp
@@ -127,3 +127,28 @@
 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"
+
+
+
+

-- 
Gerrit-Project: binutils-gdb
Gerrit-Branch: master
Gerrit-Change-Id: I90a28feb55b388fb46461a096c5db08b6b0bd427
Gerrit-Change-Number: 269
Gerrit-PatchSet: 5
Gerrit-Owner: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-CC: Joel Brobecker <brobecker@adacore.com>
Gerrit-MessageType: newpatchset

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

* [review v6] gdb/mi: Add -max-results parameter to some -symbol-info-* commands
       [not found] <gerrit.1571909344000.I90a28feb55b388fb46461a096c5db08b6b0bd427@gnutoolchain-gerrit.osci.io>
                   ` (3 preceding siblings ...)
  2019-11-22 17:33 ` [review v5] " Andrew Burgess (Code Review)
@ 2019-11-26 23:26 ` Andrew Burgess (Code Review)
  2019-11-26 23:40 ` [review v7] " Andrew Burgess (Code Review)
                   ` (21 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrew Burgess (Code Review) @ 2019-11-26 23:26 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker

Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/269
......................................................................

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

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.
	(global_symbol_searcher::is_suitable_msymbol): New function.
	(global_symbol_searcher::expand_symtabs): New function.
	(global_symbol_searcher::add_matching_symbols): New function.
	(global_symbol_searcher::add_matching_msymbols): New function.
	(global_symbol_searcher::search_symbols): Move most of the content
	into the new functions above, and call them as needed.
	* symtab.h: Add 'set' include.
	(global_symbol_searcher) <set_max_seach_results>: New member
	function.
	(global_symbol_searcher) <m_max_search_results>: New member
	variable.
	(global_symbol_searcher) <expand_symtabs>: New member function.
	(global_symbol_searcher) <add_matching_symbols>: New member
	function.
	(global_symbol_searcher) <add_matching_msymbols>: New member
	function.
	(global_symbol_searcher) <is_suitable_msymbol>: New member
	function.

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
---
M gdb/ChangeLog
M gdb/doc/ChangeLog
M gdb/doc/gdb.texinfo
M gdb/mi/mi-symbol-cmds.c
M gdb/symtab.c
M gdb/symtab.h
M gdb/testsuite/ChangeLog
M gdb/testsuite/gdb.mi/mi-sym-info.exp
8 files changed, 428 insertions(+), 211 deletions(-)



diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 4df7cb8..9ee0545 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,34 @@
 2019-11-26  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* 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.
+	(global_symbol_searcher::is_suitable_msymbol): New function.
+	(global_symbol_searcher::expand_symtabs): New function.
+	(global_symbol_searcher::add_matching_symbols): New function.
+	(global_symbol_searcher::add_matching_msymbols): New function.
+	(global_symbol_searcher::search_symbols): Move most of the content
+	into the new functions above, and call them as needed.
+	* symtab.h: Add 'set' include.
+	(global_symbol_searcher) <set_max_seach_results>: New member
+	function.
+	(global_symbol_searcher) <m_max_search_results>: New member
+	variable.
+	(global_symbol_searcher) <expand_symtabs>: New member function.
+	(global_symbol_searcher) <add_matching_symbols>: New member
+	function.
+	(global_symbol_searcher) <add_matching_msymbols>: New member
+	function.
+	(global_symbol_searcher) <is_suitable_msymbol>: New member
+	function.
+
+2019-11-26  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* 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.
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 7d7e265..d518760 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,5 +1,10 @@
 2019-11-26  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* doc/gdb.texinfo (GDB/MI Symbol Query): Add documentation of
+	-max-results to some -symbol-info-* commands.
+
+2019-11-26  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* doc/gdb.texinfo (GDB/MI Symbol Query): Document new MI command
 	-symbol-info-module-functions and -symbol-info-module-variables.
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index ee6c95f..0b54e52 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -33899,6 +33899,7 @@
  -symbol-info-functions [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
 @end smallexample
 
 @noindent
@@ -33914,6 +33915,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}.
@@ -34145,6 +34151,8 @@
 
 @smallexample
  -symbol-info-modules [--name @var{name_regexp}]
+                      [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34155,6 +34163,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}.
@@ -34199,6 +34212,8 @@
 
 @smallexample
  -symbol-info-types [--name @var{name_regexp}]
+                    [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34212,6 +34227,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}.
@@ -34259,6 +34279,8 @@
  -symbol-info-variables [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34274,6 +34296,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 4d94dc0..117a72f 100644
--- a/gdb/mi/mi-symbol-cmds.c
+++ b/gdb/mi/mi-symbol-cmds.c
@@ -111,11 +111,13 @@
 
 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)
 {
   global_symbol_searcher sym_search (kind, regexp);
   sym_search.set_symbol_type_regexp (t_regexp);
   sym_search.set_exclude_minsyms (exclude_minsyms);
+  sym_search.set_max_search_results (max_results);
   std::vector<symbol_search> symbols = sym_search.search ();
   ui_out *uiout = current_uiout;
   int i = 0;
@@ -172,19 +174,21 @@
 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 }
   };
 
@@ -210,10 +214,19 @@
 	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.
@@ -345,15 +358,17 @@
 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 }
   };
 
@@ -371,10 +386,19 @@
 	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.  */
@@ -382,15 +406,17 @@
 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 }
   };
 
@@ -408,10 +434,19 @@
 	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 89160ad..e57ef28 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4364,8 +4364,8 @@
   return false;
 }
 
-/* Helper function for sort_search_symbols_remove_dups and qsort.  Can only
-   sort symbols, not minimal symbols.  */
+/* Helper function for std::sort on symbol_search objects.  Can only sort
+   symbols, not minimal symbols.  */
 
 int
 symbol_search::compare_search_syms (const symbol_search &sym_a,
@@ -4426,15 +4426,239 @@
   return treg.exec (printed_sym_type_name.c_str (), 0, NULL, 0) == 0;
 }
 
+/* See symtab.h.  */
 
-/* Sort the symbols in RESULT and remove duplicates.  */
-
-static void
-sort_search_symbols_remove_dups (std::vector<symbol_search> *result)
+bool
+global_symbol_searcher::is_suitable_msymbol
+	(const enum search_domain kind, const minimal_symbol *msymbol)
 {
-  std::sort (result->begin (), result->end ());
-  result->erase (std::unique (result->begin (), result->end ()),
-		 result->end ());
+  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};
+
+  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);
+}
+
+/* See symtab.h.  */
+
+bool
+global_symbol_searcher::expand_symtabs
+	(objfile *objfile, const gdb::optional<compiled_regex> &preg) const
+{
+  enum search_domain kind = m_kind;
+  bool found_misc = false;
+
+  if (objfile->sf)
+    objfile->sf->qf->expand_symtabs_matching
+      (objfile,
+       [&] (const char *filename, bool basenames)
+       {
+	 return file_matches (filename, filenames, basenames);
+       },
+       lookup_name_info::match_any (),
+       [&] (const char *symname)
+       {
+	 return (!preg.has_value ()
+		 || preg->exec (symname, 0, NULL, 0) == 0);
+       },
+       NULL,
+       kind);
+
+  /* Here, we search through the minimal symbol tables for functions and
+     variables that match, and force their symbols to be read.  This is in
+     particular necessary for demangled variable names, which are no longer
+     put into the partial symbol tables.  The symbol will then be found
+     during the scan of symtabs later.
+
+     For functions, find_pc_symtab should succeed if we have debug info for
+     the function, for variables we have to call
+     lookup_symbol_in_objfile_from_linkage_name to determine if the
+     variable has debug info.  If the lookup fails, set found_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 (filenames.empty ()
+      && (kind == VARIABLES_DOMAIN || kind == FUNCTIONS_DOMAIN))
+    {
+      for (minimal_symbol *msymbol : objfile->msymbols ())
+	{
+	  QUIT;
+
+	  if (msymbol->created_by_gdb)
+	    continue;
+
+	  if (is_suitable_msymbol (kind, msymbol))
+	    {
+	      if (!preg.has_value ()
+		  || preg->exec (msymbol->natural_name (), 0,
+				 NULL, 0) == 0)
+		{
+		  /* 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 (),
+			  VAR_DOMAIN)
+			 .symbol == NULL))
+		    found_misc = true;
+		}
+	    }
+	}
+    }
+
+  return found_misc;
+}
+
+/* See symtab.h.  */
+bool
+global_symbol_searcher::add_matching_symbols
+	(objfile *objfile,
+	 const gdb::optional<compiled_regex> &preg,
+	 const gdb::optional<compiled_regex> &treg,
+	 std::set<symbol_search> *result_set) const
+{
+  enum search_domain kind = m_kind;
+
+  /* Add matching symbols (if not already present).  */
+  for (compunit_symtab *cust : objfile->compunits ())
+    {
+      const struct blockvector *bv  = COMPUNIT_BLOCKVECTOR (cust);
+
+      for (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, filenames, false)
+		   || ((basenames_may_differ
+			|| file_matches (lbasename (real_symtab->filename),
+					 filenames, true))
+		       && file_matches (symtab_to_fullname (real_symtab),
+					filenames, false)))
+		  && ((!preg.has_value ()
+		       || preg->exec (sym->natural_name (), 0,
+				      NULL, 0) == 0)
+		      && ((kind == VARIABLES_DOMAIN
+			   && SYMBOL_CLASS (sym) != LOC_TYPEDEF
+			   && SYMBOL_CLASS (sym) != LOC_UNRESOLVED
+			   && SYMBOL_CLASS (sym) != LOC_BLOCK
+			   /* LOC_CONST can be used for more than
+			      just enums, e.g., c++ static const
+			      members.  We only want to skip enums
+			      here.  */
+			   && !(SYMBOL_CLASS (sym) == LOC_CONST
+				&& (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 (m_max_search_results == -1
+		      || result_set->size () < m_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;
+}
+
+/* See symtab.h.  */
+
+bool
+global_symbol_searcher::add_matching_msymbols
+	(objfile *objfile, const gdb::optional<compiled_regex> &preg,
+	 std::vector<symbol_search> *results) const
+{
+  enum search_domain kind = m_kind;
+
+  for (minimal_symbol *msymbol : objfile->msymbols ())
+    {
+      QUIT;
+
+      if (msymbol->created_by_gdb)
+	continue;
+
+      if (is_suitable_msymbol (kind, msymbol))
+	{
+	  if (!preg.has_value ()
+	      || preg->exec (msymbol->natural_name (), 0,
+			     NULL, 0) == 0)
+	    {
+	      /* For functions we can do a quick check of whether the
+		 symbol might be found via find_pc_symtab.  */
+	      if (kind != FUNCTIONS_DOMAIN
+		  || (find_pc_compunit_symtab
+		      (MSYMBOL_VALUE_ADDRESS (objfile, msymbol))
+		      == NULL))
+		{
+		  if (lookup_symbol_in_objfile_from_linkage_name
+		      (objfile, msymbol->linkage_name (),
+		       VAR_DOMAIN).symbol == NULL)
+		    {
+		      /* Matching msymbol, add it to the results list.  */
+		      if (m_max_search_results == -1
+			  || (results->size () < m_max_search_results))
+			results->emplace_back (GLOBAL_BLOCK, msymbol, objfile);
+		      else
+			return false;
+		    }
+		}
+	    }
+	}
+    }
+
+  return true;
 }
 
 /* See symtab.h.  */
@@ -4442,35 +4666,11 @@
 std::vector<symbol_search>
 global_symbol_searcher::search () const
 {
-  const struct blockvector *bv;
-  const struct block *b;
-  int i = 0;
-  struct block_iterator iter;
-  struct symbol *sym;
-  int found_misc = 0;
-  static const enum minimal_symbol_type types[]
-    = {mst_data, mst_text, mst_unknown};
-  static const enum minimal_symbol_type types2[]
-    = {mst_bss, mst_file_text, mst_unknown};
-  static const enum minimal_symbol_type types3[]
-    = {mst_file_data, mst_solib_trampoline, mst_unknown};
-  static const enum minimal_symbol_type types4[]
-    = {mst_file_bss, mst_text_gnu_ifunc, mst_unknown};
-  enum minimal_symbol_type ourtype;
-  enum minimal_symbol_type ourtype2;
-  enum minimal_symbol_type ourtype3;
-  enum minimal_symbol_type ourtype4;
-  std::vector<symbol_search> result;
   gdb::optional<compiled_regex> preg;
   gdb::optional<compiled_regex> treg;
 
   gdb_assert (m_kind != ALL_DOMAIN);
 
-  ourtype = types[m_kind];
-  ourtype2 = types2[m_kind];
-  ourtype3 = types3[m_kind];
-  ourtype4 = types4[m_kind];
-
   if (m_symbol_name_regexp != NULL)
     {
       const char *symbol_name_regexp = m_symbol_name_regexp;
@@ -4523,187 +4723,36 @@
 		    _("Invalid m_symbol_namregexp"));
     }
 
-  /* Search through the partial symtabs *first* for all symbols
-     matching the m_symbol_namregexp.  That way we don't have to reproduce all of
-     the machinery below.  */
-  expand_symtabs_matching ([&] (const char *filename, bool basenames)
-			   {
-			     return file_matches (filename, filenames,
-						  basenames);
-			   },
-			   lookup_name_info::match_any (),
-			   [&] (const char *symname)
-			   {
-			     return (!preg.has_value ()
-				     || preg->exec (symname,
-						    0, NULL, 0) == 0);
-			   },
-			   NULL,
-			   m_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 (filenames.empty () && (m_kind == VARIABLES_DOMAIN
-			     || m_kind == FUNCTIONS_DOMAIN))
-    {
-      for (objfile *objfile : current_program_space->objfiles ())
-	{
-	  for (minimal_symbol *msymbol : objfile->msymbols ())
-	    {
-	      QUIT;
-
-	      if (msymbol->created_by_gdb)
-		continue;
-
-	      if (MSYMBOL_TYPE (msymbol) == ourtype
-		  || MSYMBOL_TYPE (msymbol) == ourtype2
-		  || MSYMBOL_TYPE (msymbol) == ourtype3
-		  || MSYMBOL_TYPE (msymbol) == ourtype4)
-		{
-		  if (!preg.has_value ()
-		      || preg->exec (msymbol->natural_name (), 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 (m_kind == FUNCTIONS_DOMAIN
-			  ? (find_pc_compunit_symtab
-			     (MSYMBOL_VALUE_ADDRESS (objfile, msymbol))
-			     == NULL)
-			  : (lookup_symbol_in_objfile_from_linkage_name
-			     (objfile, msymbol->linkage_name (), 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);
+      /* Expand symtabs within objfile that possibly contain matching
+	 symbols.  */
+      found_misc |= expand_symtabs (objfile, preg);
 
-		  QUIT;
-
-		  /* Check first sole REAL_SYMTAB->FILENAME.  It does
-		     not need to be a substring of symtab_to_fullname as
-		     it may contain "./" etc.  */
-		  if ((file_matches (real_symtab->filename, filenames, false)
-		       || ((basenames_may_differ
-			    || file_matches (lbasename (real_symtab->filename),
-					     filenames, true))
-			   && file_matches (symtab_to_fullname (real_symtab),
-					    filenames, false)))
-		      && ((!preg.has_value ()
-			   || preg->exec (sym->natural_name (), 0,
-					  NULL, 0) == 0)
-			  && ((m_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)))
-			      || (m_kind == FUNCTIONS_DOMAIN
-				  && SYMBOL_CLASS (sym) == LOC_BLOCK
-				  && (!treg.has_value ()
-				      || treg_matches_sym_type_name (*treg,
-								     sym)))
-			      || (m_kind == TYPES_DOMAIN
-				  && SYMBOL_CLASS (sym) == LOC_TYPEDEF
-				  && SYMBOL_DOMAIN (sym) != MODULE_DOMAIN)
-			      || (m_kind == MODULES_DOMAIN
-				  && SYMBOL_DOMAIN (sym) == MODULE_DOMAIN
-				  && SYMBOL_LINE (sym) != 0))))
-		    {
-		      /* match */
-		      result.emplace_back (i, sym);
-		    }
-		}
-	    }
-	}
+      /* Find matching symbols within OBJFILE and add them in to
+	 RESULT_SET.  */
+      if (!add_matching_symbols (objfile, preg, treg, &result_set))
+	break;
     }
 
-  if (!result.empty ())
-    sort_search_symbols_remove_dups (&result);
+  /* 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 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 m_symbol_namregexp, then never give a minimal symbol,
-     as we assume that a minimal symbol does not have a type.  */
-
-  if ((found_misc || (filenames.empty () && m_kind != FUNCTIONS_DOMAIN))
+  /* 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 || (filenames.empty () && m_kind == VARIABLES_DOMAIN))
       && !m_exclude_minsyms
       && !treg.has_value ())
     {
+      gdb_assert (m_kind == VARIABLES_DOMAIN || m_kind == FUNCTIONS_DOMAIN);
       for (objfile *objfile : current_program_space->objfiles ())
-	{
-	  for (minimal_symbol *msymbol : objfile->msymbols ())
-	    {
-	      QUIT;
-
-	      if (msymbol->created_by_gdb)
-		continue;
-
-	      if (MSYMBOL_TYPE (msymbol) == ourtype
-		  || MSYMBOL_TYPE (msymbol) == ourtype2
-		  || MSYMBOL_TYPE (msymbol) == ourtype3
-		  || MSYMBOL_TYPE (msymbol) == ourtype4)
-		{
-		  if (!preg.has_value ()
-		      || preg->exec (msymbol->natural_name (), 0,
-				     NULL, 0) == 0)
-		    {
-		      /* For functions we can do a quick check of whether the
-			 symbol might be found via find_pc_symtab.  */
-		      if (m_kind != FUNCTIONS_DOMAIN
-			  || (find_pc_compunit_symtab
-			      (MSYMBOL_VALUE_ADDRESS (objfile, msymbol))
-			      == NULL))
-			{
-			  if (lookup_symbol_in_objfile_from_linkage_name
-			      (objfile, msymbol->linkage_name (), VAR_DOMAIN)
-			      .symbol == NULL)
-			    {
-			      /* match */
-			      result.emplace_back (i, msymbol, objfile);
-			    }
-			}
-		    }
-		}
-	    }
-	}
+	if (!add_matching_msymbols (objfile, preg, &result))
+	  break;
     }
 
   return result;
diff --git a/gdb/symtab.h b/gdb/symtab.h
index efb55b2..dddf9c3 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -35,6 +35,8 @@
 #include "completer.h"
 #include "gdb-demangle.h"
 
+#include <set>
+
 /* Opaque declarations.  */
 struct ui_file;
 struct frame_info;
@@ -2077,6 +2079,12 @@
     m_exclude_minsyms = exclude_minsyms;
   }
 
+  /* Set the maximum number of search results to be returned.  */
+  void set_max_search_results (int max_search_results)
+  {
+    m_max_search_results = max_search_results;
+  }
+
   /* Search the symbols from all objfiles in the current program space
      looking for matches as defined by the current state of this object.
 
@@ -2109,6 +2117,41 @@
   /* When this flag is false then minsyms that match M_SYMBOL_REGEXP will
      be included in the results, otherwise they are excluded.  */
   bool m_exclude_minsyms = false;
+
+  /* Maximum number of search results, set to -1 for unlimited, otherwise
+     set to a positive value to limit the number of results returned.  */
+  int m_max_search_results = -1;
+
+  /* Expand symtabs in OBJFILE that match PREG, are of type M_KIND.  Return
+     true if any msymbols were seen that we should later consider adding to
+     the results list.  */
+  bool expand_symtabs (objfile *objfile,
+		       const gdb::optional<compiled_regex> &preg) const;
+
+  /* Add symbols from symtabs in OBJFILE that match PREG, and TREG, and are
+     of type M_KIND, 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), otherwise return true.  Returning
+     true does not indicate that any results were added, just that we
+     didn't _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
+  bool add_matching_symbols (objfile *objfile,
+			     const gdb::optional<compiled_regex> &preg,
+			     const gdb::optional<compiled_regex> &treg,
+			     std::set<symbol_search> *result_set) const;
+
+  /* Add msymbols from OBJFILE that match PREG and M_KIND, 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.  Returning true
+     does not indicate that any results were added, just that we didn't
+     _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
+  bool add_matching_msymbols (objfile *objfile,
+			      const gdb::optional<compiled_regex> &preg,
+			      std::vector<symbol_search> *results) const;
+
+  /* Return true if MSYMBOL is of type KIND.  */
+  static bool is_suitable_msymbol (const enum search_domain kind,
+				   const minimal_symbol *msymbol);
 };
 
 /* When searching for Fortran symbols within modules (functions/variables)
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 7121ad4..c272ffb 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,9 @@
 2019-11-26  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* gdb.mi/mi-sym-info.exp: Add tests for -max-results parameter.
+
+2019-11-26  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* gdb.mi/mi-fortran-modules.exp: Add additional tests for
 	-symbol-info-module-functions and -symbol-info-module-variables.
 
diff --git a/gdb/testsuite/gdb.mi/mi-sym-info.exp b/gdb/testsuite/gdb.mi/mi-sym-info.exp
index 33fe865..80468a4 100644
--- a/gdb/testsuite/gdb.mi/mi-sym-info.exp
+++ b/gdb/testsuite/gdb.mi/mi-sym-info.exp
@@ -127,3 +127,28 @@
 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"
+
+
+
+

-- 
Gerrit-Project: binutils-gdb
Gerrit-Branch: master
Gerrit-Change-Id: I90a28feb55b388fb46461a096c5db08b6b0bd427
Gerrit-Change-Number: 269
Gerrit-PatchSet: 6
Gerrit-Owner: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-CC: Joel Brobecker <brobecker@adacore.com>
Gerrit-MessageType: newpatchset

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

* [review v7] gdb/mi: Add -max-results parameter to some -symbol-info-* commands
       [not found] <gerrit.1571909344000.I90a28feb55b388fb46461a096c5db08b6b0bd427@gnutoolchain-gerrit.osci.io>
                   ` (4 preceding siblings ...)
  2019-11-26 23:26 ` [review v6] " Andrew Burgess (Code Review)
@ 2019-11-26 23:40 ` Andrew Burgess (Code Review)
  2019-11-27  5:31 ` Simon Marchi (Code Review)
                   ` (20 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrew Burgess (Code Review) @ 2019-11-26 23:40 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker

Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/269
......................................................................

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

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.
	(global_symbol_searcher::is_suitable_msymbol): New function.
	(global_symbol_searcher::expand_symtabs): New function.
	(global_symbol_searcher::add_matching_symbols): New function.
	(global_symbol_searcher::add_matching_msymbols): New function.
	(global_symbol_searcher::search_symbols): Move most of the content
	into the new functions above, and call them as needed.
	* symtab.h: Add 'set' include.
	(global_symbol_searcher) <set_max_seach_results>: New member
	function.
	(global_symbol_searcher) <m_max_search_results>: New member
	variable.
	(global_symbol_searcher) <expand_symtabs>: New member function.
	(global_symbol_searcher) <add_matching_symbols>: New member
	function.
	(global_symbol_searcher) <add_matching_msymbols>: New member
	function.
	(global_symbol_searcher) <is_suitable_msymbol>: New member
	function.

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
---
M gdb/ChangeLog
M gdb/doc/ChangeLog
M gdb/doc/gdb.texinfo
M gdb/mi/mi-symbol-cmds.c
M gdb/symtab.c
M gdb/symtab.h
M gdb/testsuite/ChangeLog
M gdb/testsuite/gdb.mi/mi-sym-info.exp
8 files changed, 426 insertions(+), 210 deletions(-)



diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 4df7cb8..9ee0545 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,34 @@
 2019-11-26  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* 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.
+	(global_symbol_searcher::is_suitable_msymbol): New function.
+	(global_symbol_searcher::expand_symtabs): New function.
+	(global_symbol_searcher::add_matching_symbols): New function.
+	(global_symbol_searcher::add_matching_msymbols): New function.
+	(global_symbol_searcher::search_symbols): Move most of the content
+	into the new functions above, and call them as needed.
+	* symtab.h: Add 'set' include.
+	(global_symbol_searcher) <set_max_seach_results>: New member
+	function.
+	(global_symbol_searcher) <m_max_search_results>: New member
+	variable.
+	(global_symbol_searcher) <expand_symtabs>: New member function.
+	(global_symbol_searcher) <add_matching_symbols>: New member
+	function.
+	(global_symbol_searcher) <add_matching_msymbols>: New member
+	function.
+	(global_symbol_searcher) <is_suitable_msymbol>: New member
+	function.
+
+2019-11-26  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* 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.
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 7d7e265..d518760 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,5 +1,10 @@
 2019-11-26  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* doc/gdb.texinfo (GDB/MI Symbol Query): Add documentation of
+	-max-results to some -symbol-info-* commands.
+
+2019-11-26  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* doc/gdb.texinfo (GDB/MI Symbol Query): Document new MI command
 	-symbol-info-module-functions and -symbol-info-module-variables.
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index ee6c95f..0b54e52 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -33899,6 +33899,7 @@
  -symbol-info-functions [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
 @end smallexample
 
 @noindent
@@ -33914,6 +33915,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}.
@@ -34145,6 +34151,8 @@
 
 @smallexample
  -symbol-info-modules [--name @var{name_regexp}]
+                      [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34155,6 +34163,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}.
@@ -34199,6 +34212,8 @@
 
 @smallexample
  -symbol-info-types [--name @var{name_regexp}]
+                    [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34212,6 +34227,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}.
@@ -34259,6 +34279,8 @@
  -symbol-info-variables [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34274,6 +34296,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 4d94dc0..117a72f 100644
--- a/gdb/mi/mi-symbol-cmds.c
+++ b/gdb/mi/mi-symbol-cmds.c
@@ -111,11 +111,13 @@
 
 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)
 {
   global_symbol_searcher sym_search (kind, regexp);
   sym_search.set_symbol_type_regexp (t_regexp);
   sym_search.set_exclude_minsyms (exclude_minsyms);
+  sym_search.set_max_search_results (max_results);
   std::vector<symbol_search> symbols = sym_search.search ();
   ui_out *uiout = current_uiout;
   int i = 0;
@@ -172,19 +174,21 @@
 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 }
   };
 
@@ -210,10 +214,19 @@
 	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.
@@ -345,15 +358,17 @@
 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 }
   };
 
@@ -371,10 +386,19 @@
 	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.  */
@@ -382,15 +406,17 @@
 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 }
   };
 
@@ -408,10 +434,19 @@
 	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 ee2fff7..cbe4964 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4364,8 +4364,8 @@
   return false;
 }
 
-/* Helper function for sort_search_symbols_remove_dups and qsort.  Can only
-   sort symbols, not minimal symbols.  */
+/* Helper function for std::sort on symbol_search objects.  Can only sort
+   symbols, not minimal symbols.  */
 
 int
 symbol_search::compare_search_syms (const symbol_search &sym_a,
@@ -4426,15 +4426,238 @@
   return treg.exec (printed_sym_type_name.c_str (), 0, NULL, 0) == 0;
 }
 
+/* See symtab.h.  */
 
-/* Sort the symbols in RESULT and remove duplicates.  */
-
-static void
-sort_search_symbols_remove_dups (std::vector<symbol_search> *result)
+bool
+global_symbol_searcher::is_suitable_msymbol
+	(const enum search_domain kind, const minimal_symbol *msymbol)
 {
-  std::sort (result->begin (), result->end ());
-  result->erase (std::unique (result->begin (), result->end ()),
-		 result->end ());
+  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};
+
+  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);
+}
+
+/* See symtab.h.  */
+
+bool
+global_symbol_searcher::expand_symtabs
+	(objfile *objfile, const gdb::optional<compiled_regex> &preg) const
+{
+  enum search_domain kind = m_kind;
+  bool found_misc = false;
+
+  if (objfile->sf)
+    objfile->sf->qf->expand_symtabs_matching
+      (objfile,
+       [&] (const char *filename, bool basenames)
+       {
+	 return file_matches (filename, filenames, basenames);
+       },
+       lookup_name_info::match_any (),
+       [&] (const char *symname)
+       {
+	 return (!preg.has_value ()
+		 || preg->exec (symname, 0, NULL, 0) == 0);
+       },
+       NULL,
+       kind);
+
+  /* Here, we search through the minimal symbol tables for functions and
+     variables that match, and force their symbols to be read.  This is in
+     particular necessary for demangled variable names, which are no longer
+     put into the partial symbol tables.  The symbol will then be found
+     during the scan of symtabs later.
+
+     For functions, find_pc_symtab should succeed if we have debug info for
+     the function, for variables we have to call
+     lookup_symbol_in_objfile_from_linkage_name to determine if the
+     variable has debug info.  If the lookup fails, set found_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 (filenames.empty ()
+      && (kind == VARIABLES_DOMAIN || kind == FUNCTIONS_DOMAIN))
+    {
+      for (minimal_symbol *msymbol : objfile->msymbols ())
+	{
+	  QUIT;
+
+	  if (msymbol->created_by_gdb)
+	    continue;
+
+	  if (is_suitable_msymbol (kind, msymbol))
+	    {
+	      if (!preg.has_value ()
+		  || preg->exec (msymbol->natural_name (), 0,
+				 NULL, 0) == 0)
+		{
+		  /* 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 (),
+			  VAR_DOMAIN)
+			 .symbol == NULL))
+		    found_misc = true;
+		}
+	    }
+	}
+    }
+
+  return found_misc;
+}
+
+/* See symtab.h.  */
+bool
+global_symbol_searcher::add_matching_symbols
+	(objfile *objfile,
+	 const gdb::optional<compiled_regex> &preg,
+	 const gdb::optional<compiled_regex> &treg,
+	 std::set<symbol_search> *result_set) const
+{
+  enum search_domain kind = m_kind;
+
+  /* Add matching symbols (if not already present).  */
+  for (compunit_symtab *cust : objfile->compunits ())
+    {
+      const struct blockvector *bv  = COMPUNIT_BLOCKVECTOR (cust);
+
+      for (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, filenames, false)
+		   || ((basenames_may_differ
+			|| file_matches (lbasename (real_symtab->filename),
+					 filenames, true))
+		       && file_matches (symtab_to_fullname (real_symtab),
+					filenames, false)))
+		  && ((!preg.has_value ()
+		       || preg->exec (sym->natural_name (), 0,
+				      NULL, 0) == 0)
+		      && ((kind == VARIABLES_DOMAIN
+			   && SYMBOL_CLASS (sym) != LOC_TYPEDEF
+			   && SYMBOL_CLASS (sym) != LOC_UNRESOLVED
+			   && SYMBOL_CLASS (sym) != LOC_BLOCK
+			   /* LOC_CONST can be used for more than
+			      just enums, e.g., c++ static const
+			      members.  We only want to skip enums
+			      here.  */
+			   && !(SYMBOL_CLASS (sym) == LOC_CONST
+				&& (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 (m_max_search_results == -1
+		      || result_set->size () < m_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;
+}
+
+/* See symtab.h.  */
+
+bool
+global_symbol_searcher::add_matching_msymbols
+	(objfile *objfile, const gdb::optional<compiled_regex> &preg,
+	 std::vector<symbol_search> *results) const
+{
+  enum search_domain kind = m_kind;
+
+  for (minimal_symbol *msymbol : objfile->msymbols ())
+    {
+      QUIT;
+
+      if (msymbol->created_by_gdb)
+	continue;
+
+      if (is_suitable_msymbol (kind, msymbol))
+	{
+	  if (!preg.has_value ()
+	      || preg->exec (msymbol->natural_name (), 0,
+			     NULL, 0) == 0)
+	    {
+	      /* For functions we can do a quick check of whether the
+		 symbol might be found via find_pc_symtab.  */
+	      if (kind != FUNCTIONS_DOMAIN
+		  || (find_pc_compunit_symtab
+		      (MSYMBOL_VALUE_ADDRESS (objfile, msymbol))
+		      == NULL))
+		{
+		  if (lookup_symbol_in_objfile_from_linkage_name
+		      (objfile, msymbol->linkage_name (),
+		       VAR_DOMAIN).symbol == NULL)
+		    {
+		      /* Matching msymbol, add it to the results list.  */
+		      if (m_max_search_results == -1
+			  || (results->size () < m_max_search_results))
+			results->emplace_back (GLOBAL_BLOCK, msymbol, objfile);
+		      else
+			return false;
+		    }
+		}
+	    }
+	}
+    }
+
+  return true;
 }
 
 /* See symtab.h.  */
@@ -4442,35 +4665,11 @@
 std::vector<symbol_search>
 global_symbol_searcher::search () const
 {
-  const struct blockvector *bv;
-  const struct block *b;
-  int i = 0;
-  struct block_iterator iter;
-  struct symbol *sym;
-  int found_misc = 0;
-  static const enum minimal_symbol_type types[]
-    = {mst_data, mst_text, mst_unknown};
-  static const enum minimal_symbol_type types2[]
-    = {mst_bss, mst_file_text, mst_unknown};
-  static const enum minimal_symbol_type types3[]
-    = {mst_file_data, mst_solib_trampoline, mst_unknown};
-  static const enum minimal_symbol_type types4[]
-    = {mst_file_bss, mst_text_gnu_ifunc, mst_unknown};
-  enum minimal_symbol_type ourtype;
-  enum minimal_symbol_type ourtype2;
-  enum minimal_symbol_type ourtype3;
-  enum minimal_symbol_type ourtype4;
-  std::vector<symbol_search> result;
   gdb::optional<compiled_regex> preg;
   gdb::optional<compiled_regex> treg;
 
   gdb_assert (m_kind != ALL_DOMAIN);
 
-  ourtype = types[m_kind];
-  ourtype2 = types2[m_kind];
-  ourtype3 = types3[m_kind];
-  ourtype4 = types4[m_kind];
-
   if (m_symbol_name_regexp != NULL)
     {
       const char *symbol_name_regexp = m_symbol_name_regexp;
@@ -4523,187 +4722,36 @@
 		    _("Invalid regexp"));
     }
 
-  /* Search through the partial symtabs *first* for all symbols matching
-     the m_symbol_name_regexp (in preg).  That way we don't have to
-     reproduce all of the machinery below.  */
-  expand_symtabs_matching ([&] (const char *filename, bool basenames)
-			   {
-			     return file_matches (filename, filenames,
-						  basenames);
-			   },
-			   lookup_name_info::match_any (),
-			   [&] (const char *symname)
-			   {
-			     return (!preg.has_value ()
-				     || preg->exec (symname,
-						    0, NULL, 0) == 0);
-			   },
-			   NULL,
-			   m_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 (filenames.empty () && (m_kind == VARIABLES_DOMAIN
-			     || m_kind == FUNCTIONS_DOMAIN))
-    {
-      for (objfile *objfile : current_program_space->objfiles ())
-	{
-	  for (minimal_symbol *msymbol : objfile->msymbols ())
-	    {
-	      QUIT;
-
-	      if (msymbol->created_by_gdb)
-		continue;
-
-	      if (MSYMBOL_TYPE (msymbol) == ourtype
-		  || MSYMBOL_TYPE (msymbol) == ourtype2
-		  || MSYMBOL_TYPE (msymbol) == ourtype3
-		  || MSYMBOL_TYPE (msymbol) == ourtype4)
-		{
-		  if (!preg.has_value ()
-		      || preg->exec (msymbol->natural_name (), 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 (m_kind == FUNCTIONS_DOMAIN
-			  ? (find_pc_compunit_symtab
-			     (MSYMBOL_VALUE_ADDRESS (objfile, msymbol))
-			     == NULL)
-			  : (lookup_symbol_in_objfile_from_linkage_name
-			     (objfile, msymbol->linkage_name (), 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);
+      /* Expand symtabs within objfile that possibly contain matching
+	 symbols.  */
+      found_misc |= expand_symtabs (objfile, preg);
 
-		  QUIT;
-
-		  /* Check first sole REAL_SYMTAB->FILENAME.  It does
-		     not need to be a substring of symtab_to_fullname as
-		     it may contain "./" etc.  */
-		  if ((file_matches (real_symtab->filename, filenames, false)
-		       || ((basenames_may_differ
-			    || file_matches (lbasename (real_symtab->filename),
-					     filenames, true))
-			   && file_matches (symtab_to_fullname (real_symtab),
-					    filenames, false)))
-		      && ((!preg.has_value ()
-			   || preg->exec (sym->natural_name (), 0,
-					  NULL, 0) == 0)
-			  && ((m_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)))
-			      || (m_kind == FUNCTIONS_DOMAIN
-				  && SYMBOL_CLASS (sym) == LOC_BLOCK
-				  && (!treg.has_value ()
-				      || treg_matches_sym_type_name (*treg,
-								     sym)))
-			      || (m_kind == TYPES_DOMAIN
-				  && SYMBOL_CLASS (sym) == LOC_TYPEDEF
-				  && SYMBOL_DOMAIN (sym) != MODULE_DOMAIN)
-			      || (m_kind == MODULES_DOMAIN
-				  && SYMBOL_DOMAIN (sym) == MODULE_DOMAIN
-				  && SYMBOL_LINE (sym) != 0))))
-		    {
-		      /* match */
-		      result.emplace_back (i, sym);
-		    }
-		}
-	    }
-	}
+      /* Find matching symbols within OBJFILE and add them in to
+	 RESULT_SET.  */
+      if (!add_matching_symbols (objfile, preg, treg, &result_set))
+	break;
     }
 
-  if (!result.empty ())
-    sort_search_symbols_remove_dups (&result);
+  /* 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 there are no debug symbols, then add matching minsyms.  But if the
-     user wants to see symbols matching a type m_symbol_type_regexp, then
-     never give a minimal symbol, as we assume that a minimal symbol does
-     not have a type.  */
-
-  if ((found_misc || (filenames.empty () && m_kind != FUNCTIONS_DOMAIN))
+     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 || (filenames.empty () && m_kind == VARIABLES_DOMAIN))
       && !m_exclude_minsyms
       && !treg.has_value ())
     {
+      gdb_assert (m_kind == VARIABLES_DOMAIN || m_kind == FUNCTIONS_DOMAIN);
       for (objfile *objfile : current_program_space->objfiles ())
-	{
-	  for (minimal_symbol *msymbol : objfile->msymbols ())
-	    {
-	      QUIT;
-
-	      if (msymbol->created_by_gdb)
-		continue;
-
-	      if (MSYMBOL_TYPE (msymbol) == ourtype
-		  || MSYMBOL_TYPE (msymbol) == ourtype2
-		  || MSYMBOL_TYPE (msymbol) == ourtype3
-		  || MSYMBOL_TYPE (msymbol) == ourtype4)
-		{
-		  if (!preg.has_value ()
-		      || preg->exec (msymbol->natural_name (), 0,
-				     NULL, 0) == 0)
-		    {
-		      /* For functions we can do a quick check of whether the
-			 symbol might be found via find_pc_symtab.  */
-		      if (m_kind != FUNCTIONS_DOMAIN
-			  || (find_pc_compunit_symtab
-			      (MSYMBOL_VALUE_ADDRESS (objfile, msymbol))
-			      == NULL))
-			{
-			  if (lookup_symbol_in_objfile_from_linkage_name
-			      (objfile, msymbol->linkage_name (), VAR_DOMAIN)
-			      .symbol == NULL)
-			    {
-			      /* match */
-			      result.emplace_back (i, msymbol, objfile);
-			    }
-			}
-		    }
-		}
-	    }
-	}
+	if (!add_matching_msymbols (objfile, preg, &result))
+	  break;
     }
 
   return result;
diff --git a/gdb/symtab.h b/gdb/symtab.h
index efb55b2..dddf9c3 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -35,6 +35,8 @@
 #include "completer.h"
 #include "gdb-demangle.h"
 
+#include <set>
+
 /* Opaque declarations.  */
 struct ui_file;
 struct frame_info;
@@ -2077,6 +2079,12 @@
     m_exclude_minsyms = exclude_minsyms;
   }
 
+  /* Set the maximum number of search results to be returned.  */
+  void set_max_search_results (int max_search_results)
+  {
+    m_max_search_results = max_search_results;
+  }
+
   /* Search the symbols from all objfiles in the current program space
      looking for matches as defined by the current state of this object.
 
@@ -2109,6 +2117,41 @@
   /* When this flag is false then minsyms that match M_SYMBOL_REGEXP will
      be included in the results, otherwise they are excluded.  */
   bool m_exclude_minsyms = false;
+
+  /* Maximum number of search results, set to -1 for unlimited, otherwise
+     set to a positive value to limit the number of results returned.  */
+  int m_max_search_results = -1;
+
+  /* Expand symtabs in OBJFILE that match PREG, are of type M_KIND.  Return
+     true if any msymbols were seen that we should later consider adding to
+     the results list.  */
+  bool expand_symtabs (objfile *objfile,
+		       const gdb::optional<compiled_regex> &preg) const;
+
+  /* Add symbols from symtabs in OBJFILE that match PREG, and TREG, and are
+     of type M_KIND, 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), otherwise return true.  Returning
+     true does not indicate that any results were added, just that we
+     didn't _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
+  bool add_matching_symbols (objfile *objfile,
+			     const gdb::optional<compiled_regex> &preg,
+			     const gdb::optional<compiled_regex> &treg,
+			     std::set<symbol_search> *result_set) const;
+
+  /* Add msymbols from OBJFILE that match PREG and M_KIND, 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.  Returning true
+     does not indicate that any results were added, just that we didn't
+     _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
+  bool add_matching_msymbols (objfile *objfile,
+			      const gdb::optional<compiled_regex> &preg,
+			      std::vector<symbol_search> *results) const;
+
+  /* Return true if MSYMBOL is of type KIND.  */
+  static bool is_suitable_msymbol (const enum search_domain kind,
+				   const minimal_symbol *msymbol);
 };
 
 /* When searching for Fortran symbols within modules (functions/variables)
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 7121ad4..c272ffb 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,9 @@
 2019-11-26  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* gdb.mi/mi-sym-info.exp: Add tests for -max-results parameter.
+
+2019-11-26  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* gdb.mi/mi-fortran-modules.exp: Add additional tests for
 	-symbol-info-module-functions and -symbol-info-module-variables.
 
diff --git a/gdb/testsuite/gdb.mi/mi-sym-info.exp b/gdb/testsuite/gdb.mi/mi-sym-info.exp
index 33fe865..80468a4 100644
--- a/gdb/testsuite/gdb.mi/mi-sym-info.exp
+++ b/gdb/testsuite/gdb.mi/mi-sym-info.exp
@@ -127,3 +127,28 @@
 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"
+
+
+
+

-- 
Gerrit-Project: binutils-gdb
Gerrit-Branch: master
Gerrit-Change-Id: I90a28feb55b388fb46461a096c5db08b6b0bd427
Gerrit-Change-Number: 269
Gerrit-PatchSet: 7
Gerrit-Owner: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-CC: Joel Brobecker <brobecker@adacore.com>
Gerrit-MessageType: newpatchset

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

* [review v7] gdb/mi: Add -max-results parameter to some -symbol-info-* commands
       [not found] <gerrit.1571909344000.I90a28feb55b388fb46461a096c5db08b6b0bd427@gnutoolchain-gerrit.osci.io>
                   ` (5 preceding siblings ...)
  2019-11-26 23:40 ` [review v7] " Andrew Burgess (Code Review)
@ 2019-11-27  5:31 ` Simon Marchi (Code Review)
  2019-11-27 14:19 ` [review v8] " Andrew Burgess (Code Review)
                   ` (19 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Simon Marchi (Code Review) @ 2019-11-27  5:31 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches; +Cc: Joel Brobecker

Simon Marchi has posted comments on this change.

Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/269
......................................................................


Patch Set 7:

(8 comments)

I think the way you refactored it is very nice, it breaks the thing up in smaller operations, easier to understand.  But it's difficult to figure out what's old stuff and what's new features.  Do you think you could split this in separate patches, one that does the refactoring (split in multiple helper methods), that would have no user visible changes, and then the one that adds --max-results?

On the general design of the patch:

If I understand correctly, the --max-results value doesn't bound the expansion of symtabs without one objfile.  When we have started to expand the matching symtabs of an objfile, there's no way to stop it unless it has gone through the whole objfile, right?  So let's say you do:

 -symbol-info-functions --max-results 2 a

we'll still proceed to expand all symtabs of the objfile that have a symbol containing `a`, which may take a very long time.  And once that's done, we'll pick the first 2 of all these symbols.

I think it's a reasonable behavior for this patch, it's better to get something working first and incrementally improve.

If we think about how to optimize later: the expand_symtabs_matching method of quick_symbol_functions already takes an "expansion_notify" callback, that is called after each individual symtab expansion.  I could see that callback returning a bool, to indicate whether to continue or stop expanding symtabs.  We would add the matching symbols from the symtab to our result set in that callback, so we could stop the expansions once we have reached our limit. WDYT?

| --- gdb/symtab.c
| +++ gdb/symtab.c
| @@ -4438,0 +4436,26 @@ global_symbol_searcher::is_suitable_msymbol
| +    = {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};
| +
| +  gdb_assert (kind == VARIABLES_DOMAIN || kind == FUNCTIONS_DOMAIN);
| +  gdb_assert (kind <= sizeof (types));

PS7, Line 4445:

Shouldn't that be `<`?

| +
| +  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

PS7, Line 4452:

I know this was pre-existing code, but that seems overly
complicated/obfuscated.  There's surely a clearer way to do this, like
(not tested, and I never remember how exactly we format switch-cases)

 switch (MSYMBOL_TYPE (msymbol))
   {
     case mst_data:
     case mst_bss:
     case mst_file_data:
     case mst_file_bss:
       return kind == VARIABLES_DOMAIN;

     case mst_text:
     case mst_file_text:
     case mst_solib_trampoline:
     case mst_text_gnu_ifunc:
       return kind == FUNCTIONS_DOMAIN;

     default:
       return false;
   }

| +	  || MSYMBOL_TYPE (msymbol) == ourtype2
| +	  || MSYMBOL_TYPE (msymbol) == ourtype3
| +	  || MSYMBOL_TYPE (msymbol) == ourtype4);
| +}
| +
| +/* See symtab.h.  */
| +
| +bool
| +global_symbol_searcher::expand_symtabs

 ...

| @@ -4438,0 +4504,54 @@ global_symbol_searcher::expand_symtabs
| +	  if (msymbol->created_by_gdb)
| +	    continue;
| +
| +	  if (is_suitable_msymbol (kind, msymbol))
| +	    {
| +	      if (!preg.has_value ()
| +		  || preg->exec (msymbol->natural_name (), 0,
| +				 NULL, 0) == 0)
| +		{
| +		  /* An important side-effect of these lookup functions is
| +		     to expand the symbol table if msymbol is found, for
| +		     the benefit of the next loop on compunits.  */

PS7, Line 4515:

I guess this comment isn't really meaningful anymore the way it is
stated, since the loop it refers to is not there anymore.  It's
perhaps still important, but just needs to be reformulated.

| +		  if (kind == FUNCTIONS_DOMAIN
| +		      ? (find_pc_compunit_symtab
| +			 (MSYMBOL_VALUE_ADDRESS (objfile, msymbol))
| +			 == NULL)
| +		      : (lookup_symbol_in_objfile_from_linkage_name
| +			 (objfile, msymbol->linkage_name (),
| +			  VAR_DOMAIN)
| +			 .symbol == NULL))
| +		    found_misc = true;
| +		}
| +	    }
| +	}
| +    }
| +
| +  return found_misc;
| +}
| +
| +/* See symtab.h.  */
| +bool

PS7, Line 4534:

Missing newline before this.

| +global_symbol_searcher::add_matching_symbols
| +	(objfile *objfile,
| +	 const gdb::optional<compiled_regex> &preg,
| +	 const gdb::optional<compiled_regex> &treg,
| +	 std::set<symbol_search> *result_set) const
| +{
| +  enum search_domain kind = m_kind;
| +
| +  /* Add matching symbols (if not already present).  */
| +  for (compunit_symtab *cust : objfile->compunits ())
| +    {
| +      const struct blockvector *bv  = COMPUNIT_BLOCKVECTOR (cust);
| +
| +      for (int i = GLOBAL_BLOCK; i <= STATIC_BLOCK; i++)

PS7, Line 4548:

Not for this patch, but I think we could eventually write this as

 for (block_enum block : { GLOBAL_BLOCK, STATIC_BLOCK })

I find it more expressive of what we're trying to do.

| +	{
| +	  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);
| +

 ...

| @@ -4590,17 +4725,4 @@ global_symbol_searcher::search () const
| -			     (objfile, msymbol->linkage_name (), VAR_DOMAIN)
| -			     .symbol == NULL))
| -			found_misc = 1;
| -		    }
| -		}
| -	    }
| -	}
| -    }
| -
| +  bool found_misc = false;

PS7, Line 4725:

Do you know why this is called `found_misc`?  Wouldn't it make more
sense to call it found_minsym?

| +  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);
| --- gdb/symtab.h
| +++ gdb/symtab.h
| @@ -2106,6 +2114,19 @@ private:
|    /* Regular expression to match against the symbol type.  */
|    const char *m_symbol_type_regexp = nullptr;
|  
|    /* When this flag is false then minsyms that match M_SYMBOL_REGEXP will
|       be included in the results, otherwise they are excluded.  */
|    bool m_exclude_minsyms = false;
| +
| +  /* Maximum number of search results, set to -1 for unlimited, otherwise
| +     set to a positive value to limit the number of results returned.  */
| +  int m_max_search_results = -1;

PS7, Line 2123:

It might simplfy the code (avoid having to check for -1) to make this
field a size_t and using SIZE_MAX for "no limit".

| +
| +  /* Expand symtabs in OBJFILE that match PREG, are of type M_KIND.  Return
| +     true if any msymbols were seen that we should later consider adding to
| +     the results list.  */
| +  bool expand_symtabs (objfile *objfile,
| +		       const gdb::optional<compiled_regex> &preg) const;
| +
| +  /* Add symbols from symtabs in OBJFILE that match PREG, and TREG, and are
| +     of type M_KIND, to the results set RESULTS_SET.  Return false if we

 ...

| @@ -2112,0 +2136,19 @@ private:
| +     didn't _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
| +  bool add_matching_symbols (objfile *objfile,
| +			     const gdb::optional<compiled_regex> &preg,
| +			     const gdb::optional<compiled_regex> &treg,
| +			     std::set<symbol_search> *result_set) const;
| +
| +  /* Add msymbols from OBJFILE that match PREG and M_KIND, 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.  Returning true

PS7, Line 2145:

That looks stale?

| +     does not indicate that any results were added, just that we didn't
| +     _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
| +  bool add_matching_msymbols (objfile *objfile,
| +			      const gdb::optional<compiled_regex> &preg,
| +			      std::vector<symbol_search> *results) const;
| +
| +  /* Return true if MSYMBOL is of type KIND.  */
| +  static bool is_suitable_msymbol (const enum search_domain kind,
| +				   const minimal_symbol *msymbol);

-- 
Gerrit-Project: binutils-gdb
Gerrit-Branch: master
Gerrit-Change-Id: I90a28feb55b388fb46461a096c5db08b6b0bd427
Gerrit-Change-Number: 269
Gerrit-PatchSet: 7
Gerrit-Owner: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-CC: Joel Brobecker <brobecker@adacore.com>
Gerrit-CC: Simon Marchi <simon.marchi@polymtl.ca>
Gerrit-Comment-Date: Wed, 27 Nov 2019 05:31:10 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
Gerrit-MessageType: comment

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

* [review v8] gdb/mi: Add -max-results parameter to some -symbol-info-* commands
       [not found] <gerrit.1571909344000.I90a28feb55b388fb46461a096c5db08b6b0bd427@gnutoolchain-gerrit.osci.io>
                   ` (6 preceding siblings ...)
  2019-11-27  5:31 ` Simon Marchi (Code Review)
@ 2019-11-27 14:19 ` Andrew Burgess (Code Review)
  2019-11-27 14:21 ` Andrew Burgess (Code Review)
                   ` (18 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrew Burgess (Code Review) @ 2019-11-27 14:19 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker, Simon Marchi

Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/269
......................................................................

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

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.
	(global_symbol_searcher::is_suitable_msymbol): New function.
	(global_symbol_searcher::expand_symtabs): New function.
	(global_symbol_searcher::add_matching_symbols): New function.
	(global_symbol_searcher::add_matching_msymbols): New function.
	(global_symbol_searcher::search_symbols): Move most of the content
	into the new functions above, and call them as needed.
	* symtab.h: Add 'set' include.
	(global_symbol_searcher) <set_max_seach_results>: New member
	function.
	(global_symbol_searcher) <m_max_search_results>: New member
	variable.
	(global_symbol_searcher) <expand_symtabs>: New member function.
	(global_symbol_searcher) <add_matching_symbols>: New member
	function.
	(global_symbol_searcher) <add_matching_msymbols>: New member
	function.
	(global_symbol_searcher) <is_suitable_msymbol>: New member
	function.

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
---
M gdb/ChangeLog
M gdb/doc/ChangeLog
M gdb/doc/gdb.texinfo
M gdb/mi/mi-symbol-cmds.c
M gdb/symtab.c
M gdb/symtab.h
M gdb/testsuite/ChangeLog
M gdb/testsuite/gdb.mi/mi-sym-info.exp
8 files changed, 426 insertions(+), 210 deletions(-)



diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 718d340..5f8d5d2 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,34 @@
 2019-11-27  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* 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.
+	(global_symbol_searcher::is_suitable_msymbol): New function.
+	(global_symbol_searcher::expand_symtabs): New function.
+	(global_symbol_searcher::add_matching_symbols): New function.
+	(global_symbol_searcher::add_matching_msymbols): New function.
+	(global_symbol_searcher::search_symbols): Move most of the content
+	into the new functions above, and call them as needed.
+	* symtab.h: Add 'set' include.
+	(global_symbol_searcher) <set_max_seach_results>: New member
+	function.
+	(global_symbol_searcher) <m_max_search_results>: New member
+	variable.
+	(global_symbol_searcher) <expand_symtabs>: New member function.
+	(global_symbol_searcher) <add_matching_symbols>: New member
+	function.
+	(global_symbol_searcher) <add_matching_msymbols>: New member
+	function.
+	(global_symbol_searcher) <is_suitable_msymbol>: New member
+	function.
+
+2019-11-27  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* 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.
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 54b65ef..97fd476 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,5 +1,10 @@
 2019-11-27  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* doc/gdb.texinfo (GDB/MI Symbol Query): Add documentation of
+	-max-results to some -symbol-info-* commands.
+
+2019-11-27  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* doc/gdb.texinfo (GDB/MI Symbol Query): Document new MI command
 	-symbol-info-module-functions and -symbol-info-module-variables.
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index e04aac9..976127a 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -33899,6 +33899,7 @@
  -symbol-info-functions [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
 @end smallexample
 
 @noindent
@@ -33914,6 +33915,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}.
@@ -34145,6 +34151,8 @@
 
 @smallexample
  -symbol-info-modules [--name @var{name_regexp}]
+                      [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34155,6 +34163,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}.
@@ -34199,6 +34212,8 @@
 
 @smallexample
  -symbol-info-types [--name @var{name_regexp}]
+                    [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34212,6 +34227,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}.
@@ -34259,6 +34279,8 @@
  -symbol-info-variables [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34274,6 +34296,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 8133239..94417c3 100644
--- a/gdb/mi/mi-symbol-cmds.c
+++ b/gdb/mi/mi-symbol-cmds.c
@@ -111,11 +111,13 @@
 
 static void
 mi_symbol_info (enum search_domain kind, const char *name_regexp,
-		const char *type_regexp, bool exclude_minsyms)
+		const char *type_regexp, bool exclude_minsyms,
+		int max_results)
 {
   global_symbol_searcher sym_search (kind, name_regexp);
   sym_search.set_symbol_type_regexp (type_regexp);
   sym_search.set_exclude_minsyms (exclude_minsyms);
+  sym_search.set_max_search_results (max_results);
   std::vector<symbol_search> symbols = sym_search.search ();
   ui_out *uiout = current_uiout;
   int i = 0;
@@ -172,19 +174,21 @@
 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 }
   };
 
@@ -210,10 +214,19 @@
 	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);
 }
 
 /* Helper for mi_info_module_functions_or_variables.  Display the results
@@ -382,15 +395,17 @@
 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 }
   };
 
@@ -408,10 +423,19 @@
 	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.  */
@@ -419,15 +443,17 @@
 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 }
   };
 
@@ -445,10 +471,19 @@
 	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 8f46321..e2e7c62b 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4367,8 +4367,8 @@
   return false;
 }
 
-/* Helper function for sort_search_symbols_remove_dups and qsort.  Can only
-   sort symbols, not minimal symbols.  */
+/* Helper function for std::sort on symbol_search objects.  Can only sort
+   symbols, not minimal symbols.  */
 
 int
 symbol_search::compare_search_syms (const symbol_search &sym_a,
@@ -4429,15 +4429,238 @@
   return treg.exec (printed_sym_type_name.c_str (), 0, NULL, 0) == 0;
 }
 
+/* See symtab.h.  */
 
-/* Sort the symbols in RESULT and remove duplicates.  */
-
-static void
-sort_search_symbols_remove_dups (std::vector<symbol_search> *result)
+bool
+global_symbol_searcher::is_suitable_msymbol
+	(const enum search_domain kind, const minimal_symbol *msymbol)
 {
-  std::sort (result->begin (), result->end ());
-  result->erase (std::unique (result->begin (), result->end ()),
-		 result->end ());
+  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};
+
+  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);
+}
+
+/* See symtab.h.  */
+
+bool
+global_symbol_searcher::expand_symtabs
+	(objfile *objfile, const gdb::optional<compiled_regex> &preg) const
+{
+  enum search_domain kind = m_kind;
+  bool found_misc = false;
+
+  if (objfile->sf)
+    objfile->sf->qf->expand_symtabs_matching
+      (objfile,
+       [&] (const char *filename, bool basenames)
+       {
+	 return file_matches (filename, filenames, basenames);
+       },
+       lookup_name_info::match_any (),
+       [&] (const char *symname)
+       {
+	 return (!preg.has_value ()
+		 || preg->exec (symname, 0, NULL, 0) == 0);
+       },
+       NULL,
+       kind);
+
+  /* Here, we search through the minimal symbol tables for functions and
+     variables that match, and force their symbols to be read.  This is in
+     particular necessary for demangled variable names, which are no longer
+     put into the partial symbol tables.  The symbol will then be found
+     during the scan of symtabs later.
+
+     For functions, find_pc_symtab should succeed if we have debug info for
+     the function, for variables we have to call
+     lookup_symbol_in_objfile_from_linkage_name to determine if the
+     variable has debug info.  If the lookup fails, set found_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 (filenames.empty ()
+      && (kind == VARIABLES_DOMAIN || kind == FUNCTIONS_DOMAIN))
+    {
+      for (minimal_symbol *msymbol : objfile->msymbols ())
+	{
+	  QUIT;
+
+	  if (msymbol->created_by_gdb)
+	    continue;
+
+	  if (is_suitable_msymbol (kind, msymbol))
+	    {
+	      if (!preg.has_value ()
+		  || preg->exec (msymbol->natural_name (), 0,
+				 NULL, 0) == 0)
+		{
+		  /* 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 (),
+			  VAR_DOMAIN)
+			 .symbol == NULL))
+		    found_misc = true;
+		}
+	    }
+	}
+    }
+
+  return found_misc;
+}
+
+/* See symtab.h.  */
+bool
+global_symbol_searcher::add_matching_symbols
+	(objfile *objfile,
+	 const gdb::optional<compiled_regex> &preg,
+	 const gdb::optional<compiled_regex> &treg,
+	 std::set<symbol_search> *result_set) const
+{
+  enum search_domain kind = m_kind;
+
+  /* Add matching symbols (if not already present).  */
+  for (compunit_symtab *cust : objfile->compunits ())
+    {
+      const struct blockvector *bv  = COMPUNIT_BLOCKVECTOR (cust);
+
+      for (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, filenames, false)
+		   || ((basenames_may_differ
+			|| file_matches (lbasename (real_symtab->filename),
+					 filenames, true))
+		       && file_matches (symtab_to_fullname (real_symtab),
+					filenames, false)))
+		  && ((!preg.has_value ()
+		       || preg->exec (sym->natural_name (), 0,
+				      NULL, 0) == 0)
+		      && ((kind == VARIABLES_DOMAIN
+			   && SYMBOL_CLASS (sym) != LOC_TYPEDEF
+			   && SYMBOL_CLASS (sym) != LOC_UNRESOLVED
+			   && SYMBOL_CLASS (sym) != LOC_BLOCK
+			   /* LOC_CONST can be used for more than
+			      just enums, e.g., c++ static const
+			      members.  We only want to skip enums
+			      here.  */
+			   && !(SYMBOL_CLASS (sym) == LOC_CONST
+				&& (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 (m_max_search_results == -1
+		      || result_set->size () < m_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;
+}
+
+/* See symtab.h.  */
+
+bool
+global_symbol_searcher::add_matching_msymbols
+	(objfile *objfile, const gdb::optional<compiled_regex> &preg,
+	 std::vector<symbol_search> *results) const
+{
+  enum search_domain kind = m_kind;
+
+  for (minimal_symbol *msymbol : objfile->msymbols ())
+    {
+      QUIT;
+
+      if (msymbol->created_by_gdb)
+	continue;
+
+      if (is_suitable_msymbol (kind, msymbol))
+	{
+	  if (!preg.has_value ()
+	      || preg->exec (msymbol->natural_name (), 0,
+			     NULL, 0) == 0)
+	    {
+	      /* For functions we can do a quick check of whether the
+		 symbol might be found via find_pc_symtab.  */
+	      if (kind != FUNCTIONS_DOMAIN
+		  || (find_pc_compunit_symtab
+		      (MSYMBOL_VALUE_ADDRESS (objfile, msymbol))
+		      == NULL))
+		{
+		  if (lookup_symbol_in_objfile_from_linkage_name
+		      (objfile, msymbol->linkage_name (),
+		       VAR_DOMAIN).symbol == NULL)
+		    {
+		      /* Matching msymbol, add it to the results list.  */
+		      if (m_max_search_results == -1
+			  || (results->size () < m_max_search_results))
+			results->emplace_back (GLOBAL_BLOCK, msymbol, objfile);
+		      else
+			return false;
+		    }
+		}
+	    }
+	}
+    }
+
+  return true;
 }
 
 /* See symtab.h.  */
@@ -4445,35 +4668,11 @@
 std::vector<symbol_search>
 global_symbol_searcher::search () const
 {
-  const struct blockvector *bv;
-  const struct block *b;
-  int i = 0;
-  struct block_iterator iter;
-  struct symbol *sym;
-  int found_misc = 0;
-  static const enum minimal_symbol_type types[]
-    = {mst_data, mst_text, mst_unknown};
-  static const enum minimal_symbol_type types2[]
-    = {mst_bss, mst_file_text, mst_unknown};
-  static const enum minimal_symbol_type types3[]
-    = {mst_file_data, mst_solib_trampoline, mst_unknown};
-  static const enum minimal_symbol_type types4[]
-    = {mst_file_bss, mst_text_gnu_ifunc, mst_unknown};
-  enum minimal_symbol_type ourtype;
-  enum minimal_symbol_type ourtype2;
-  enum minimal_symbol_type ourtype3;
-  enum minimal_symbol_type ourtype4;
-  std::vector<symbol_search> result;
   gdb::optional<compiled_regex> preg;
   gdb::optional<compiled_regex> treg;
 
   gdb_assert (m_kind != ALL_DOMAIN);
 
-  ourtype = types[m_kind];
-  ourtype2 = types2[m_kind];
-  ourtype3 = types3[m_kind];
-  ourtype4 = types4[m_kind];
-
   if (m_symbol_name_regexp != NULL)
     {
       const char *symbol_name_regexp = m_symbol_name_regexp;
@@ -4526,187 +4725,36 @@
 		    _("Invalid regexp"));
     }
 
-  /* Search through the partial symtabs *first* for all symbols matching
-     the m_symbol_name_regexp (in preg).  That way we don't have to
-     reproduce all of the machinery below.  */
-  expand_symtabs_matching ([&] (const char *filename, bool basenames)
-			   {
-			     return file_matches (filename, filenames,
-						  basenames);
-			   },
-			   lookup_name_info::match_any (),
-			   [&] (const char *symname)
-			   {
-			     return (!preg.has_value ()
-				     || preg->exec (symname,
-						    0, NULL, 0) == 0);
-			   },
-			   NULL,
-			   m_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 (filenames.empty () && (m_kind == VARIABLES_DOMAIN
-			     || m_kind == FUNCTIONS_DOMAIN))
-    {
-      for (objfile *objfile : current_program_space->objfiles ())
-	{
-	  for (minimal_symbol *msymbol : objfile->msymbols ())
-	    {
-	      QUIT;
-
-	      if (msymbol->created_by_gdb)
-		continue;
-
-	      if (MSYMBOL_TYPE (msymbol) == ourtype
-		  || MSYMBOL_TYPE (msymbol) == ourtype2
-		  || MSYMBOL_TYPE (msymbol) == ourtype3
-		  || MSYMBOL_TYPE (msymbol) == ourtype4)
-		{
-		  if (!preg.has_value ()
-		      || preg->exec (msymbol->natural_name (), 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 (m_kind == FUNCTIONS_DOMAIN
-			  ? (find_pc_compunit_symtab
-			     (MSYMBOL_VALUE_ADDRESS (objfile, msymbol))
-			     == NULL)
-			  : (lookup_symbol_in_objfile_from_linkage_name
-			     (objfile, msymbol->linkage_name (), 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);
+      /* Expand symtabs within objfile that possibly contain matching
+	 symbols.  */
+      found_misc |= expand_symtabs (objfile, preg);
 
-		  QUIT;
-
-		  /* Check first sole REAL_SYMTAB->FILENAME.  It does
-		     not need to be a substring of symtab_to_fullname as
-		     it may contain "./" etc.  */
-		  if ((file_matches (real_symtab->filename, filenames, false)
-		       || ((basenames_may_differ
-			    || file_matches (lbasename (real_symtab->filename),
-					     filenames, true))
-			   && file_matches (symtab_to_fullname (real_symtab),
-					    filenames, false)))
-		      && ((!preg.has_value ()
-			   || preg->exec (sym->natural_name (), 0,
-					  NULL, 0) == 0)
-			  && ((m_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)))
-			      || (m_kind == FUNCTIONS_DOMAIN
-				  && SYMBOL_CLASS (sym) == LOC_BLOCK
-				  && (!treg.has_value ()
-				      || treg_matches_sym_type_name (*treg,
-								     sym)))
-			      || (m_kind == TYPES_DOMAIN
-				  && SYMBOL_CLASS (sym) == LOC_TYPEDEF
-				  && SYMBOL_DOMAIN (sym) != MODULE_DOMAIN)
-			      || (m_kind == MODULES_DOMAIN
-				  && SYMBOL_DOMAIN (sym) == MODULE_DOMAIN
-				  && SYMBOL_LINE (sym) != 0))))
-		    {
-		      /* match */
-		      result.emplace_back (i, sym);
-		    }
-		}
-	    }
-	}
+      /* Find matching symbols within OBJFILE and add them in to
+	 RESULT_SET.  */
+      if (!add_matching_symbols (objfile, preg, treg, &result_set))
+	break;
     }
 
-  if (!result.empty ())
-    sort_search_symbols_remove_dups (&result);
+  /* 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 there are no debug symbols, then add matching minsyms.  But if the
-     user wants to see symbols matching a type m_symbol_type_regexp, then
-     never give a minimal symbol, as we assume that a minimal symbol does
-     not have a type.  */
-
-  if ((found_misc || (filenames.empty () && m_kind != FUNCTIONS_DOMAIN))
+     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 || (filenames.empty () && m_kind == VARIABLES_DOMAIN))
       && !m_exclude_minsyms
       && !treg.has_value ())
     {
+      gdb_assert (m_kind == VARIABLES_DOMAIN || m_kind == FUNCTIONS_DOMAIN);
       for (objfile *objfile : current_program_space->objfiles ())
-	{
-	  for (minimal_symbol *msymbol : objfile->msymbols ())
-	    {
-	      QUIT;
-
-	      if (msymbol->created_by_gdb)
-		continue;
-
-	      if (MSYMBOL_TYPE (msymbol) == ourtype
-		  || MSYMBOL_TYPE (msymbol) == ourtype2
-		  || MSYMBOL_TYPE (msymbol) == ourtype3
-		  || MSYMBOL_TYPE (msymbol) == ourtype4)
-		{
-		  if (!preg.has_value ()
-		      || preg->exec (msymbol->natural_name (), 0,
-				     NULL, 0) == 0)
-		    {
-		      /* For functions we can do a quick check of whether the
-			 symbol might be found via find_pc_symtab.  */
-		      if (m_kind != FUNCTIONS_DOMAIN
-			  || (find_pc_compunit_symtab
-			      (MSYMBOL_VALUE_ADDRESS (objfile, msymbol))
-			      == NULL))
-			{
-			  if (lookup_symbol_in_objfile_from_linkage_name
-			      (objfile, msymbol->linkage_name (), VAR_DOMAIN)
-			      .symbol == NULL)
-			    {
-			      /* match */
-			      result.emplace_back (i, msymbol, objfile);
-			    }
-			}
-		    }
-		}
-	    }
-	}
+	if (!add_matching_msymbols (objfile, preg, &result))
+	  break;
     }
 
   return result;
diff --git a/gdb/symtab.h b/gdb/symtab.h
index a52f2a5..270b226 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -35,6 +35,8 @@
 #include "completer.h"
 #include "gdb-demangle.h"
 
+#include <set>
+
 /* Opaque declarations.  */
 struct ui_file;
 struct frame_info;
@@ -2091,6 +2093,12 @@
     m_exclude_minsyms = exclude_minsyms;
   }
 
+  /* Set the maximum number of search results to be returned.  */
+  void set_max_search_results (int max_search_results)
+  {
+    m_max_search_results = max_search_results;
+  }
+
   /* Search the symbols from all objfiles in the current program space
      looking for matches as defined by the current state of this object.
 
@@ -2123,6 +2131,41 @@
   /* When this flag is false then minsyms that match M_SYMBOL_REGEXP will
      be included in the results, otherwise they are excluded.  */
   bool m_exclude_minsyms = false;
+
+  /* Maximum number of search results, set to -1 for unlimited, otherwise
+     set to a positive value to limit the number of results returned.  */
+  int m_max_search_results = -1;
+
+  /* Expand symtabs in OBJFILE that match PREG, are of type M_KIND.  Return
+     true if any msymbols were seen that we should later consider adding to
+     the results list.  */
+  bool expand_symtabs (objfile *objfile,
+		       const gdb::optional<compiled_regex> &preg) const;
+
+  /* Add symbols from symtabs in OBJFILE that match PREG, and TREG, and are
+     of type M_KIND, 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), otherwise return true.  Returning
+     true does not indicate that any results were added, just that we
+     didn't _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
+  bool add_matching_symbols (objfile *objfile,
+			     const gdb::optional<compiled_regex> &preg,
+			     const gdb::optional<compiled_regex> &treg,
+			     std::set<symbol_search> *result_set) const;
+
+  /* Add msymbols from OBJFILE that match PREG and M_KIND, 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.  Returning true
+     does not indicate that any results were added, just that we didn't
+     _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
+  bool add_matching_msymbols (objfile *objfile,
+			      const gdb::optional<compiled_regex> &preg,
+			      std::vector<symbol_search> *results) const;
+
+  /* Return true if MSYMBOL is of type KIND.  */
+  static bool is_suitable_msymbol (const enum search_domain kind,
+				   const minimal_symbol *msymbol);
 };
 
 /* When searching for Fortran symbols within modules (functions/variables)
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 115a13f..2cee7c3 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,9 @@
 2019-11-27  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* gdb.mi/mi-sym-info.exp: Add tests for -max-results parameter.
+
+2019-11-27  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* gdb.mi/mi-fortran-modules.exp: Add additional tests for
 	-symbol-info-module-functions and -symbol-info-module-variables.
 
diff --git a/gdb/testsuite/gdb.mi/mi-sym-info.exp b/gdb/testsuite/gdb.mi/mi-sym-info.exp
index 33fe865..80468a4 100644
--- a/gdb/testsuite/gdb.mi/mi-sym-info.exp
+++ b/gdb/testsuite/gdb.mi/mi-sym-info.exp
@@ -127,3 +127,28 @@
 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"
+
+
+
+

-- 
Gerrit-Project: binutils-gdb
Gerrit-Branch: master
Gerrit-Change-Id: I90a28feb55b388fb46461a096c5db08b6b0bd427
Gerrit-Change-Number: 269
Gerrit-PatchSet: 8
Gerrit-Owner: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-CC: Joel Brobecker <brobecker@adacore.com>
Gerrit-CC: Simon Marchi <simon.marchi@polymtl.ca>
Gerrit-MessageType: newpatchset

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

* [review v8] gdb/mi: Add -max-results parameter to some -symbol-info-* commands
       [not found] <gerrit.1571909344000.I90a28feb55b388fb46461a096c5db08b6b0bd427@gnutoolchain-gerrit.osci.io>
                   ` (7 preceding siblings ...)
  2019-11-27 14:19 ` [review v8] " Andrew Burgess (Code Review)
@ 2019-11-27 14:21 ` Andrew Burgess (Code Review)
  2019-12-02 17:57 ` Andrew Burgess (Code Review)
                   ` (17 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrew Burgess (Code Review) @ 2019-11-27 14:21 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Joel Brobecker

Andrew Burgess has posted comments on this change.

Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/269
......................................................................


Patch Set 8:

Thanks for the feedback, I'll get to this ASAP.


-- 
Gerrit-Project: binutils-gdb
Gerrit-Branch: master
Gerrit-Change-Id: I90a28feb55b388fb46461a096c5db08b6b0bd427
Gerrit-Change-Number: 269
Gerrit-PatchSet: 8
Gerrit-Owner: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-Reviewer: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-CC: Joel Brobecker <brobecker@adacore.com>
Gerrit-CC: Simon Marchi <simon.marchi@polymtl.ca>
Gerrit-Comment-Date: Wed, 27 Nov 2019 14:21:49 +0000
Gerrit-HasComments: No
Gerrit-Has-Labels: No
Gerrit-MessageType: comment

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

* [review v8] gdb/mi: Add -max-results parameter to some -symbol-info-* commands
       [not found] <gerrit.1571909344000.I90a28feb55b388fb46461a096c5db08b6b0bd427@gnutoolchain-gerrit.osci.io>
                   ` (8 preceding siblings ...)
  2019-11-27 14:21 ` Andrew Burgess (Code Review)
@ 2019-12-02 17:57 ` Andrew Burgess (Code Review)
  2019-12-02 18:40 ` Simon Marchi (Code Review)
                   ` (16 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrew Burgess (Code Review) @ 2019-12-02 17:57 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Joel Brobecker

Andrew Burgess has posted comments on this change.

Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/269
......................................................................


Patch Set 8:

> Patch Set 7:
> 
> (8 comments)
> 
> I think the way you refactored it is very nice, it breaks the thing up in smaller operations, easier to understand.  But it's difficult to figure out what's old stuff and what's new features.  Do you think you could split this in separate patches, one that does the refactoring (split in multiple helper methods), that would have no user visible changes, and then the one that adds --max-results?
> 
> On the general design of the patch:
> 
> If I understand correctly, the --max-results value doesn't bound the expansion of symtabs without one objfile.  When we have started to expand the matching symtabs of an objfile, there's no way to stop it unless it has gone through the whole objfile, right?  So let's say you do:
> 
>  -symbol-info-functions --max-results 2 a
> 
> we'll still proceed to expand all symtabs of the objfile that have a symbol containing `a`, which may take a very long time.  And once that's done, we'll pick the first 2 of all these symbols.
> 
> I think it's a reasonable behavior for this patch, it's better to get something working first and incrementally improve.
> 
> If we think about how to optimize later: the expand_symtabs_matching method of quick_symbol_functions already takes an "expansion_notify" callback, that is called after each individual symtab expansion.  I could see that callback returning a bool, to indicate whether to continue or stop expanding symtabs.  We would add the matching symbols from the symtab to our result set in that callback, so we could stop the expansions once we have reached our limit. WDYT?

The problem that worried me most here was the difference between when something needs expanding, and when something is already expanded.

So right now we expand matching symtabs within an objfile, which might do nothing is the symtabs are already expanded, then we rewalk the symtabs and add matching symbols.

If we use the current "just expanded symtab" callback then this only triggers if something gets expanded, if it was already expanded then I don't think we see the callback, so we'd then need to walk all the symtabs again to catch any already expanded symtabs.

This will create strange ordering artifacts where results will appear in a different order the first call vs later calls.

What we really need is a "visit matching symtabs" type function, that applies the same logic as expand, but triggers the callback even for symtabs that are already expanded.


-- 
Gerrit-Project: binutils-gdb
Gerrit-Branch: master
Gerrit-Change-Id: I90a28feb55b388fb46461a096c5db08b6b0bd427
Gerrit-Change-Number: 269
Gerrit-PatchSet: 8
Gerrit-Owner: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-Reviewer: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-CC: Joel Brobecker <brobecker@adacore.com>
Gerrit-CC: Simon Marchi <simon.marchi@polymtl.ca>
Gerrit-Comment-Date: Mon, 02 Dec 2019 17:57:39 +0000
Gerrit-HasComments: No
Gerrit-Has-Labels: No
Gerrit-MessageType: comment

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

* [review v8] gdb/mi: Add -max-results parameter to some -symbol-info-* commands
       [not found] <gerrit.1571909344000.I90a28feb55b388fb46461a096c5db08b6b0bd427@gnutoolchain-gerrit.osci.io>
                   ` (9 preceding siblings ...)
  2019-12-02 17:57 ` Andrew Burgess (Code Review)
@ 2019-12-02 18:40 ` Simon Marchi (Code Review)
  2019-12-02 19:15 ` [review v9] " Andrew Burgess (Code Review)
                   ` (15 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Simon Marchi (Code Review) @ 2019-12-02 18:40 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches; +Cc: Joel Brobecker

Simon Marchi has posted comments on this change.

Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/269
......................................................................


Patch Set 8:

> The problem that worried me most here was the difference between when something needs expanding, and when something is already expanded.
> 
> So right now we expand matching symtabs within an objfile, which might do nothing is the symtabs are already expanded, then we rewalk the symtabs and add matching symbols.
> 
> If we use the current "just expanded symtab" callback then this only triggers if something gets expanded, if it was already expanded then I don't think we see the callback, so we'd then need to walk all the symtabs again to catch any already expanded symtabs.
> 
> This will create strange ordering artifacts where results will appear in a different order the first call vs later calls.
> 
> What we really need is a "visit matching symtabs" type function, that applies the same logic as expand, but triggers the callback even for symtabs that are already expanded.

Ahh good point.  So we indeed need a "visit matching symtab, expanding if needed" callback.


-- 
Gerrit-Project: binutils-gdb
Gerrit-Branch: master
Gerrit-Change-Id: I90a28feb55b388fb46461a096c5db08b6b0bd427
Gerrit-Change-Number: 269
Gerrit-PatchSet: 8
Gerrit-Owner: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-Reviewer: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-CC: Joel Brobecker <brobecker@adacore.com>
Gerrit-CC: Simon Marchi <simon.marchi@polymtl.ca>
Gerrit-Comment-Date: Mon, 02 Dec 2019 18:40:18 +0000
Gerrit-HasComments: No
Gerrit-Has-Labels: No
Gerrit-MessageType: comment

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

* [review v9] gdb/mi: Add -max-results parameter to some -symbol-info-* commands
       [not found] <gerrit.1571909344000.I90a28feb55b388fb46461a096c5db08b6b0bd427@gnutoolchain-gerrit.osci.io>
                   ` (10 preceding siblings ...)
  2019-12-02 18:40 ` Simon Marchi (Code Review)
@ 2019-12-02 19:15 ` Andrew Burgess (Code Review)
  2019-12-02 19:18 ` Andrew Burgess (Code Review)
                   ` (14 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrew Burgess (Code Review) @ 2019-12-02 19:15 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker, Simon Marchi

Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/269
......................................................................

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

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.

One other thing to note is that the global_symbol_searcher::search by
default returns UINT_MAX results, there's no longer a mechanism to
return an unlimited number of results, though hopefully this will not
be a huge issue.

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 (global_symbol_searcher::add_matching_symbols): Change
	return type to bool, don't add new results if we have enough
	already.
	(global_symbol_searcher::add_matching_msymbols): Likewise.
	(global_symbol_searcher::search): Early exit from search loop when
	we have enough results.
	* symtab.h (global_symbol_searcher) <set_max_seach_results>: New
	member function.
	(global_symbol_searcher) <m_max_search_results>: New member
	variable.
	(global_symbol_searcher) <add_matching_symbols>: Update header
	comment and change return type to bool.
	(global_symbol_searcher) <add_matching_msymbols>: Update header
	comment and change return type to bool.

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
---
M gdb/ChangeLog
M gdb/doc/ChangeLog
M gdb/doc/gdb.texinfo
M gdb/mi/mi-symbol-cmds.c
M gdb/symtab.c
M gdb/symtab.h
M gdb/testsuite/ChangeLog
M gdb/testsuite/gdb.mi/mi-sym-info.exp
8 files changed, 168 insertions(+), 21 deletions(-)



diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index a21e06c..c3199e3 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,28 @@
 2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* 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 (global_symbol_searcher::add_matching_symbols): Change
+	return type to bool, don't add new results if we have enough
+	already.
+	(global_symbol_searcher::add_matching_msymbols): Likewise.
+	(global_symbol_searcher::search): Early exit from search loop when
+	we have enough results.
+	* symtab.h (global_symbol_searcher) <set_max_seach_results>: New
+	member function.
+	(global_symbol_searcher) <m_max_search_results>: New member
+	variable.
+	(global_symbol_searcher) <add_matching_symbols>: Update header
+	comment and change return type to bool.
+	(global_symbol_searcher) <add_matching_msymbols>: Update header
+	comment and change return type to bool.
+
+2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* symtab.c (symbol_search::compare_search_syms): Update header
 	comment.
 	(global_symbol_searcher::is_suitable_msymbol): New function.
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 10e2207..df6026f 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,5 +1,10 @@
 2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* doc/gdb.texinfo (GDB/MI Symbol Query): Add documentation of
+	-max-results to some -symbol-info-* commands.
+
+2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* doc/gdb.texinfo (GDB/MI Symbol Query): Document new MI command
 	-symbol-info-module-functions and -symbol-info-module-variables.
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 6fb7e8a..544e632 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -33962,6 +33962,7 @@
  -symbol-info-functions [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
 @end smallexample
 
 @noindent
@@ -33977,6 +33978,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}.
@@ -34208,6 +34214,8 @@
 
 @smallexample
  -symbol-info-modules [--name @var{name_regexp}]
+                      [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34218,6 +34226,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}.
@@ -34262,6 +34275,8 @@
 
 @smallexample
  -symbol-info-types [--name @var{name_regexp}]
+                    [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34275,6 +34290,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}.
@@ -34322,6 +34342,8 @@
  -symbol-info-variables [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34337,6 +34359,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 6334e39..8bc6c26 100644
--- a/gdb/mi/mi-symbol-cmds.c
+++ b/gdb/mi/mi-symbol-cmds.c
@@ -111,11 +111,13 @@
 
 static void
 mi_symbol_info (enum search_domain kind, const char *name_regexp,
-		const char *type_regexp, bool exclude_minsyms)
+		const char *type_regexp, bool exclude_minsyms,
+		unsigned int max_results)
 {
   global_symbol_searcher sym_search (kind, name_regexp);
   sym_search.set_symbol_type_regexp (type_regexp);
   sym_search.set_exclude_minsyms (exclude_minsyms);
+  sym_search.set_max_search_results (max_results);
   std::vector<symbol_search> symbols = sym_search.search ();
   ui_out *uiout = current_uiout;
   int i = 0;
@@ -172,19 +174,21 @@
 static void
 mi_info_functions_or_variables (enum search_domain kind, char **argv, int argc)
 {
+  unsigned int max_results = UINT_MAX;
   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 }
   };
 
@@ -210,10 +214,19 @@
 	case NAME_REGEXP_OPT:
 	  regexp = oarg;
 	  break;
+	case MAX_RESULTS_OPT:
+	  {
+	    char *eptr = oarg;
+	    long val = strtol (oarg, &eptr, 10);
+	    if (oarg == eptr || val > UINT_MAX || val < 0)
+	      error (_("invalid value for --max-results argument"));
+	    max_results = (unsigned int) val;
+	  }
+	  break;
 	}
     }
 
-  mi_symbol_info (kind, regexp, t_regexp, exclude_minsyms);
+  mi_symbol_info (kind, regexp, t_regexp, exclude_minsyms, max_results);
 }
 
 /* Helper for mi_info_module_functions_or_variables.  Display the results
@@ -382,15 +395,17 @@
 void
 mi_cmd_symbol_info_modules (const char *command, char **argv, int argc)
 {
+  unsigned int max_results = UINT_MAX;
   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 }
   };
 
@@ -408,10 +423,19 @@
 	case NAME_REGEXP_OPT:
 	  regexp = oarg;
 	  break;
+	case MAX_RESULTS_OPT:
+	  {
+	    char *eptr = oarg;
+	    long val = strtol (oarg, &eptr, 10);
+	    if (oarg == eptr || val > UINT_MAX || val < 0)
+	      error (_("invalid value for --max-results argument"));
+	    max_results = (unsigned 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.  */
@@ -419,15 +443,17 @@
 void
 mi_cmd_symbol_info_types (const char *command, char **argv, int argc)
 {
+  unsigned int max_results = UINT_MAX;
   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 }
   };
 
@@ -445,10 +471,19 @@
 	case NAME_REGEXP_OPT:
 	  regexp = oarg;
 	  break;
+	case MAX_RESULTS_OPT:
+	  {
+	    char *eptr = oarg;
+	    long val = strtol (oarg, &eptr, 10);
+	    if (oarg == eptr || val > UINT_MAX || val < 0)
+	      error (_("invalid value for --max-results argument"));
+	    max_results = (unsigned 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 0e92d4a..16dca72 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4534,7 +4534,7 @@
 
 /* See symtab.h.  */
 
-void
+bool
 global_symbol_searcher::add_matching_symbols
 	(objfile *objfile,
 	 const gdb::optional<compiled_regex> &preg,
@@ -4597,19 +4597,26 @@
 			      && SYMBOL_DOMAIN (sym) == MODULE_DOMAIN
 			      && SYMBOL_LINE (sym) != 0))))
 		{
-		  /* Match, insert if not already in the results.  */
-		  symbol_search ss (block, sym);
-		  if (result_set->find (ss) == result_set->end ())
-		    result_set->insert (ss);
+		  if (result_set->size () < m_max_search_results)
+		    {
+		      /* Match, insert if not already in the results.  */
+		      symbol_search ss (block, sym);
+		      if (result_set->find (ss) == result_set->end ())
+			result_set->insert (ss);
+		    }
+		  else
+		    return false;
 		}
 	    }
 	}
     }
+
+  return true;
 }
 
 /* See symtab.h.  */
 
-void
+bool
 global_symbol_searcher::add_matching_msymbols
 	(objfile *objfile, const gdb::optional<compiled_regex> &preg,
 	 std::vector<symbol_search> *results) const
@@ -4641,12 +4648,17 @@
 		       VAR_DOMAIN).symbol == NULL)
 		    {
 		      /* Matching msymbol, add it to the results list.  */
-		      results->emplace_back (GLOBAL_BLOCK, msymbol, objfile);
+		      if (results->size () < m_max_search_results)
+			results->emplace_back (GLOBAL_BLOCK, msymbol, objfile);
+		      else
+			return false;
 		    }
 		}
 	    }
 	}
     }
+
+  return true;
 }
 
 /* See symtab.h.  */
@@ -4721,7 +4733,8 @@
 
       /* Find matching symbols within OBJFILE and add them in to
 	 RESULT_SET.  */
-      add_matching_symbols (objfile, preg, treg, &result_set);
+      if (!add_matching_symbols (objfile, preg, treg, &result_set))
+	break;
     }
 
   /* Convert the result set into a sorted result list.  */
@@ -4738,7 +4751,8 @@
     {
       gdb_assert (m_kind == VARIABLES_DOMAIN || m_kind == FUNCTIONS_DOMAIN);
       for (objfile *objfile : current_program_space->objfiles ())
-	add_matching_msymbols (objfile, preg, &result);
+	if (!add_matching_msymbols (objfile, preg, &result))
+	  break;
     }
 
   return result;
diff --git a/gdb/symtab.h b/gdb/symtab.h
index f183083..d0fc20d 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -2093,6 +2093,12 @@
     m_exclude_minsyms = exclude_minsyms;
   }
 
+  /* Set the maximum number of search results to be returned.  */
+  void set_max_search_results (unsigned int max_search_results)
+  {
+    m_max_search_results = max_search_results;
+  }
+
   /* Search the symbols from all objfiles in the current program space
      looking for matches as defined by the current state of this object.
 
@@ -2126,6 +2132,10 @@
      be included in the results, otherwise they are excluded.  */
   bool m_exclude_minsyms = false;
 
+  /* Maximum number of search results.  We currently impose a hard limit
+     of UINT_MAX, there is no "unlimited".  */
+  unsigned int m_max_search_results = UINT_MAX;
+
   /* Expand symtabs in OBJFILE that match PREG, are of type M_KIND.  Return
      true if any msymbols were seen that we should later consider adding to
      the results list.  */
@@ -2133,15 +2143,23 @@
 		       const gdb::optional<compiled_regex> &preg) const;
 
   /* Add symbols from symtabs in OBJFILE that match PREG, and TREG, and are
-     of type M_KIND, to the results set RESULTS_SET.  */
-  void add_matching_symbols (objfile *objfile,
+     of type M_KIND, to the results set RESULTS_SET.  Return false if we
+     stop adding results early due to having already found too many results
+     (based on M_MAX_SEARCH_RESULTS limit), otherwise return true.
+     Returning true does not indicate that any results were added, just
+     that we didn't _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
+  bool add_matching_symbols (objfile *objfile,
 			     const gdb::optional<compiled_regex> &preg,
 			     const gdb::optional<compiled_regex> &treg,
 			     std::set<symbol_search> *result_set) const;
 
-  /* Add msymbols from OBJFILE that match PREG and M_KIND, to the
-     results vector RESULTS.  */
-  void add_matching_msymbols (objfile *objfile,
+  /* Add msymbols from OBJFILE that match PREG and M_KIND, 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 M_MAX_SEARCH_RESULTS), otherwise return true.  Returning true
+     does not indicate that any results were added, just that we didn't
+     _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
+  bool add_matching_msymbols (objfile *objfile,
 			      const gdb::optional<compiled_regex> &preg,
 			      std::vector<symbol_search> *results) const;
 
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 7fa48e3..765fb84 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,9 @@
 2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* gdb.mi/mi-sym-info.exp: Add tests for -max-results parameter.
+
+2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* gdb.mi/mi-fortran-modules.exp: Add additional tests for
 	-symbol-info-module-functions and -symbol-info-module-variables.
 
diff --git a/gdb/testsuite/gdb.mi/mi-sym-info.exp b/gdb/testsuite/gdb.mi/mi-sym-info.exp
index 33fe865..4a65bd6 100644
--- a/gdb/testsuite/gdb.mi/mi-sym-info.exp
+++ b/gdb/testsuite/gdb.mi/mi-sym-info.exp
@@ -127,3 +127,24 @@
 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"

-- 
Gerrit-Project: binutils-gdb
Gerrit-Branch: master
Gerrit-Change-Id: I90a28feb55b388fb46461a096c5db08b6b0bd427
Gerrit-Change-Number: 269
Gerrit-PatchSet: 9
Gerrit-Owner: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-Reviewer: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-CC: Joel Brobecker <brobecker@adacore.com>
Gerrit-CC: Simon Marchi <simon.marchi@polymtl.ca>
Gerrit-MessageType: newpatchset

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

* [review v9] gdb/mi: Add -max-results parameter to some -symbol-info-* commands
       [not found] <gerrit.1571909344000.I90a28feb55b388fb46461a096c5db08b6b0bd427@gnutoolchain-gerrit.osci.io>
                   ` (11 preceding siblings ...)
  2019-12-02 19:15 ` [review v9] " Andrew Burgess (Code Review)
@ 2019-12-02 19:18 ` Andrew Burgess (Code Review)
  2019-12-02 19:37 ` Simon Marchi (Code Review)
                   ` (13 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrew Burgess (Code Review) @ 2019-12-02 19:18 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Joel Brobecker

Andrew Burgess has posted comments on this change.

Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/269
......................................................................


Patch Set 9:

All points raised are, I think, addressed in the new restructuring patch.  I changed the max matches to 'unsigned int' instead of 'size_t' - is there a benefit for size_t that I'm missing?  And use UINT_MAX as the default value.  The consequence of this is that there's no truely "unlimited" matching mode any more, but I think with a limit of UINT_MAX this probably isn't a problem.


-- 
Gerrit-Project: binutils-gdb
Gerrit-Branch: master
Gerrit-Change-Id: I90a28feb55b388fb46461a096c5db08b6b0bd427
Gerrit-Change-Number: 269
Gerrit-PatchSet: 9
Gerrit-Owner: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-Reviewer: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-CC: Joel Brobecker <brobecker@adacore.com>
Gerrit-CC: Simon Marchi <simon.marchi@polymtl.ca>
Gerrit-Comment-Date: Mon, 02 Dec 2019 19:18:46 +0000
Gerrit-HasComments: No
Gerrit-Has-Labels: No
Gerrit-MessageType: comment

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

* [review v9] gdb/mi: Add -max-results parameter to some -symbol-info-* commands
       [not found] <gerrit.1571909344000.I90a28feb55b388fb46461a096c5db08b6b0bd427@gnutoolchain-gerrit.osci.io>
                   ` (12 preceding siblings ...)
  2019-12-02 19:18 ` Andrew Burgess (Code Review)
@ 2019-12-02 19:37 ` Simon Marchi (Code Review)
  2019-12-02 23:44 ` [review v10] " Andrew Burgess (Code Review)
                   ` (12 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Simon Marchi (Code Review) @ 2019-12-02 19:37 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches; +Cc: Joel Brobecker

Simon Marchi has posted comments on this change.

Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/269
......................................................................


Patch Set 9:

> Patch Set 9:
> 
> All points raised are, I think, addressed in the new restructuring patch.  I changed the max matches to 'unsigned int' instead of 'size_t' - is there a benefit for size_t that I'm missing?  And use UINT_MAX as the default value.  The consequence of this is that there's no truely "unlimited" matching mode any more, but I think with a limit of UINT_MAX this probably isn't a problem.

Only that "size_t" is guaranteed to be able to hold the largest size an object can have on the machine, so we know it is guaranteed to be large enough to hold the number of results we can possibly return before running out of memory.  In practice, unsigned int is probably large enough too, but there's no such guarantee.

In any case there is no truly "unlimited" matching mode.  In both cases (using -1 to denote unlimited or using SIZE_MAX as a maximum), the memory of the machine is the limit.


-- 
Gerrit-Project: binutils-gdb
Gerrit-Branch: master
Gerrit-Change-Id: I90a28feb55b388fb46461a096c5db08b6b0bd427
Gerrit-Change-Number: 269
Gerrit-PatchSet: 9
Gerrit-Owner: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-Reviewer: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-CC: Joel Brobecker <brobecker@adacore.com>
Gerrit-CC: Simon Marchi <simon.marchi@polymtl.ca>
Gerrit-Comment-Date: Mon, 02 Dec 2019 19:37:01 +0000
Gerrit-HasComments: No
Gerrit-Has-Labels: No
Gerrit-MessageType: comment

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

* [review v10] gdb/mi: Add -max-results parameter to some -symbol-info-* commands
       [not found] <gerrit.1571909344000.I90a28feb55b388fb46461a096c5db08b6b0bd427@gnutoolchain-gerrit.osci.io>
                   ` (13 preceding siblings ...)
  2019-12-02 19:37 ` Simon Marchi (Code Review)
@ 2019-12-02 23:44 ` Andrew Burgess (Code Review)
  2019-12-03  0:00 ` Andrew Burgess (Code Review)
                   ` (11 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrew Burgess (Code Review) @ 2019-12-02 23:44 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker, Simon Marchi

Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/269
......................................................................

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

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.

One other thing to note is that the global_symbol_searcher::search by
default returns UINT_MAX results, there's no longer a mechanism to
return an unlimited number of results, though hopefully this will not
be a huge issue.

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 (global_symbol_searcher::add_matching_symbols): Change
	return type to bool, change result container into a set, and don't
	add new results if we have enough already.
	(global_symbol_searcher::add_matching_msymbols): Change return
	type to bool, and don't add new results if we have enough already.
	(sort_search_symbols_remove_dups): Delete.
	(global_symbol_searcher::search): Early exit from search loop when
	we have enough results.  Use a std::set to collect the results
	from calling add_matching_symbols.
	* symtab.h (global_symbol_searcher) <set_max_seach_results>: New
	member function.
	(global_symbol_searcher) <m_max_search_results>: New member
	variable.
	(global_symbol_searcher) <add_matching_symbols>: Update header
	comment and change return type to bool.
	(global_symbol_searcher) <add_matching_msymbols>: Update header
	comment and change return type to bool.

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
---
M gdb/ChangeLog
M gdb/doc/ChangeLog
M gdb/doc/gdb.texinfo
M gdb/mi/mi-symbol-cmds.c
M gdb/symtab.c
M gdb/symtab.h
M gdb/testsuite/ChangeLog
M gdb/testsuite/gdb.mi/mi-sym-info.exp
8 files changed, 181 insertions(+), 35 deletions(-)



diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 53161f5..953d423 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,31 @@
 2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* 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 (global_symbol_searcher::add_matching_symbols): Change
+	return type to bool, change result container into a set, and don't
+	add new results if we have enough already.
+	(global_symbol_searcher::add_matching_msymbols): Change return
+	type to bool, and don't add new results if we have enough already.
+	(sort_search_symbols_remove_dups): Delete.
+	(global_symbol_searcher::search): Early exit from search loop when
+	we have enough results.  Use a std::set to collect the results
+	from calling add_matching_symbols.
+	* symtab.h (global_symbol_searcher) <set_max_seach_results>: New
+	member function.
+	(global_symbol_searcher) <m_max_search_results>: New member
+	variable.
+	(global_symbol_searcher) <add_matching_symbols>: Update header
+	comment and change return type to bool.
+	(global_symbol_searcher) <add_matching_msymbols>: Update header
+	comment and change return type to bool.
+
+2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* symtab.c (symbol_search::compare_search_syms): Update header
 	comment.
 	(global_symbol_searcher::is_suitable_msymbol): New function.
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 10e2207..df6026f 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,5 +1,10 @@
 2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* doc/gdb.texinfo (GDB/MI Symbol Query): Add documentation of
+	-max-results to some -symbol-info-* commands.
+
+2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* doc/gdb.texinfo (GDB/MI Symbol Query): Document new MI command
 	-symbol-info-module-functions and -symbol-info-module-variables.
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 6fb7e8a..544e632 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -33962,6 +33962,7 @@
  -symbol-info-functions [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
 @end smallexample
 
 @noindent
@@ -33977,6 +33978,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}.
@@ -34208,6 +34214,8 @@
 
 @smallexample
  -symbol-info-modules [--name @var{name_regexp}]
+                      [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34218,6 +34226,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}.
@@ -34262,6 +34275,8 @@
 
 @smallexample
  -symbol-info-types [--name @var{name_regexp}]
+                    [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34275,6 +34290,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}.
@@ -34322,6 +34342,8 @@
  -symbol-info-variables [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34337,6 +34359,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 6334e39..8bc6c26 100644
--- a/gdb/mi/mi-symbol-cmds.c
+++ b/gdb/mi/mi-symbol-cmds.c
@@ -111,11 +111,13 @@
 
 static void
 mi_symbol_info (enum search_domain kind, const char *name_regexp,
-		const char *type_regexp, bool exclude_minsyms)
+		const char *type_regexp, bool exclude_minsyms,
+		unsigned int max_results)
 {
   global_symbol_searcher sym_search (kind, name_regexp);
   sym_search.set_symbol_type_regexp (type_regexp);
   sym_search.set_exclude_minsyms (exclude_minsyms);
+  sym_search.set_max_search_results (max_results);
   std::vector<symbol_search> symbols = sym_search.search ();
   ui_out *uiout = current_uiout;
   int i = 0;
@@ -172,19 +174,21 @@
 static void
 mi_info_functions_or_variables (enum search_domain kind, char **argv, int argc)
 {
+  unsigned int max_results = UINT_MAX;
   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 }
   };
 
@@ -210,10 +214,19 @@
 	case NAME_REGEXP_OPT:
 	  regexp = oarg;
 	  break;
+	case MAX_RESULTS_OPT:
+	  {
+	    char *eptr = oarg;
+	    long val = strtol (oarg, &eptr, 10);
+	    if (oarg == eptr || val > UINT_MAX || val < 0)
+	      error (_("invalid value for --max-results argument"));
+	    max_results = (unsigned int) val;
+	  }
+	  break;
 	}
     }
 
-  mi_symbol_info (kind, regexp, t_regexp, exclude_minsyms);
+  mi_symbol_info (kind, regexp, t_regexp, exclude_minsyms, max_results);
 }
 
 /* Helper for mi_info_module_functions_or_variables.  Display the results
@@ -382,15 +395,17 @@
 void
 mi_cmd_symbol_info_modules (const char *command, char **argv, int argc)
 {
+  unsigned int max_results = UINT_MAX;
   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 }
   };
 
@@ -408,10 +423,19 @@
 	case NAME_REGEXP_OPT:
 	  regexp = oarg;
 	  break;
+	case MAX_RESULTS_OPT:
+	  {
+	    char *eptr = oarg;
+	    long val = strtol (oarg, &eptr, 10);
+	    if (oarg == eptr || val > UINT_MAX || val < 0)
+	      error (_("invalid value for --max-results argument"));
+	    max_results = (unsigned 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.  */
@@ -419,15 +443,17 @@
 void
 mi_cmd_symbol_info_types (const char *command, char **argv, int argc)
 {
+  unsigned int max_results = UINT_MAX;
   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 }
   };
 
@@ -445,10 +471,19 @@
 	case NAME_REGEXP_OPT:
 	  regexp = oarg;
 	  break;
+	case MAX_RESULTS_OPT:
+	  {
+	    char *eptr = oarg;
+	    long val = strtol (oarg, &eptr, 10);
+	    if (oarg == eptr || val > UINT_MAX || val < 0)
+	      error (_("invalid value for --max-results argument"));
+	    max_results = (unsigned 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 f3f0bd5..88b5bd8 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4534,12 +4534,12 @@
 
 /* See symtab.h.  */
 
-void
+bool
 global_symbol_searcher::add_matching_symbols
 	(objfile *objfile,
 	 const gdb::optional<compiled_regex> &preg,
 	 const gdb::optional<compiled_regex> &treg,
-	 std::vector<symbol_search> *results) const
+	 std::set<symbol_search> *result_set) const
 {
   enum search_domain kind = m_kind;
 
@@ -4597,17 +4597,26 @@
 			      && SYMBOL_DOMAIN (sym) == MODULE_DOMAIN
 			      && SYMBOL_LINE (sym) != 0))))
 		{
-		  /* Match, insert if not already in the results.  */
-		  results->emplace_back (block, sym);
+		  if (result_set->size () < m_max_search_results)
+		    {
+		      /* Match, insert if not already in the results.  */
+		      symbol_search ss (block, sym);
+		      if (result_set->find (ss) == result_set->end ())
+			result_set->insert (ss);
+		    }
+		  else
+		    return false;
 		}
 	    }
 	}
     }
+
+  return true;
 }
 
 /* See symtab.h.  */
 
-void
+bool
 global_symbol_searcher::add_matching_msymbols
 	(objfile *objfile, const gdb::optional<compiled_regex> &preg,
 	 std::vector<symbol_search> *results) const
@@ -4639,22 +4648,17 @@
 		       VAR_DOMAIN).symbol == NULL)
 		    {
 		      /* Matching msymbol, add it to the results list.  */
-		      results->emplace_back (GLOBAL_BLOCK, msymbol, objfile);
+		      if (results->size () < m_max_search_results)
+			results->emplace_back (GLOBAL_BLOCK, msymbol, objfile);
+		      else
+			return false;
 		    }
 		}
 	    }
 	}
     }
-}
 
-/* Sort the symbols in RESULT and remove duplicates.  */
-
-static void
-sort_search_symbols_remove_dups (std::vector<symbol_search> *result)
-{
-  std::sort (result->begin (), result->end ());
-  result->erase (std::unique (result->begin (), result->end ()),
-		 result->end ());
+  return true;
 }
 
 /* See symtab.h.  */
@@ -4720,20 +4724,24 @@
     }
 
   bool found_msymbol = false;
-  std::vector<symbol_search> result;
+  std::set<symbol_search> result_set;
   for (objfile *objfile : current_program_space->objfiles ())
     {
       /* Expand symtabs within objfile that possibly contain matching
 	 symbols.  */
       found_msymbol |= expand_symtabs (objfile, preg);
 
-      /* Find matching symbols within OBJFILE and add them in to the RESULT
-	 vector.  */
-      add_matching_symbols (objfile, preg, treg, &result);
+      /* Find matching symbols within OBJFILE and add them in to the
+	 RESULT_SET set.  Use a set here so that we can easily detect
+	 duplicates as we go, and can therefore track how many unique
+	 matches we have found so far.  */
+      if (!add_matching_symbols (objfile, preg, treg, &result_set))
+	break;
     }
 
-  if (!result.empty ())
-    sort_search_symbols_remove_dups (&result);
+  /* 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 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
@@ -4745,7 +4753,8 @@
     {
       gdb_assert (m_kind == VARIABLES_DOMAIN || m_kind == FUNCTIONS_DOMAIN);
       for (objfile *objfile : current_program_space->objfiles ())
-	add_matching_msymbols (objfile, preg, &result);
+	if (!add_matching_msymbols (objfile, preg, &result))
+	  break;
     }
 
   return result;
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 41abf1f..d0fc20d 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -23,6 +23,7 @@
 #include <array>
 #include <vector>
 #include <string>
+#include <set>
 #include "gdbsupport/gdb_vecs.h"
 #include "gdbtypes.h"
 #include "gdb_obstack.h"
@@ -2092,6 +2093,12 @@
     m_exclude_minsyms = exclude_minsyms;
   }
 
+  /* Set the maximum number of search results to be returned.  */
+  void set_max_search_results (unsigned int max_search_results)
+  {
+    m_max_search_results = max_search_results;
+  }
+
   /* Search the symbols from all objfiles in the current program space
      looking for matches as defined by the current state of this object.
 
@@ -2125,6 +2132,10 @@
      be included in the results, otherwise they are excluded.  */
   bool m_exclude_minsyms = false;
 
+  /* Maximum number of search results.  We currently impose a hard limit
+     of UINT_MAX, there is no "unlimited".  */
+  unsigned int m_max_search_results = UINT_MAX;
+
   /* Expand symtabs in OBJFILE that match PREG, are of type M_KIND.  Return
      true if any msymbols were seen that we should later consider adding to
      the results list.  */
@@ -2132,15 +2143,23 @@
 		       const gdb::optional<compiled_regex> &preg) const;
 
   /* Add symbols from symtabs in OBJFILE that match PREG, and TREG, and are
-     of type M_KIND, to the results vector RESULTS.  */
-  void add_matching_symbols (objfile *objfile,
+     of type M_KIND, to the results set RESULTS_SET.  Return false if we
+     stop adding results early due to having already found too many results
+     (based on M_MAX_SEARCH_RESULTS limit), otherwise return true.
+     Returning true does not indicate that any results were added, just
+     that we didn't _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
+  bool add_matching_symbols (objfile *objfile,
 			     const gdb::optional<compiled_regex> &preg,
 			     const gdb::optional<compiled_regex> &treg,
-			     std::vector<symbol_search> *results) const;
+			     std::set<symbol_search> *result_set) const;
 
-  /* Add msymbols from OBJFILE that match PREG and M_KIND, to the
-     results vector RESULTS.  */
-  void add_matching_msymbols (objfile *objfile,
+  /* Add msymbols from OBJFILE that match PREG and M_KIND, 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 M_MAX_SEARCH_RESULTS), otherwise return true.  Returning true
+     does not indicate that any results were added, just that we didn't
+     _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
+  bool add_matching_msymbols (objfile *objfile,
 			      const gdb::optional<compiled_regex> &preg,
 			      std::vector<symbol_search> *results) const;
 
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 7fa48e3..765fb84 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,9 @@
 2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* gdb.mi/mi-sym-info.exp: Add tests for -max-results parameter.
+
+2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* gdb.mi/mi-fortran-modules.exp: Add additional tests for
 	-symbol-info-module-functions and -symbol-info-module-variables.
 
diff --git a/gdb/testsuite/gdb.mi/mi-sym-info.exp b/gdb/testsuite/gdb.mi/mi-sym-info.exp
index 33fe865..4a65bd6 100644
--- a/gdb/testsuite/gdb.mi/mi-sym-info.exp
+++ b/gdb/testsuite/gdb.mi/mi-sym-info.exp
@@ -127,3 +127,24 @@
 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"

-- 
Gerrit-Project: binutils-gdb
Gerrit-Branch: master
Gerrit-Change-Id: I90a28feb55b388fb46461a096c5db08b6b0bd427
Gerrit-Change-Number: 269
Gerrit-PatchSet: 10
Gerrit-Owner: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-Reviewer: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-CC: Joel Brobecker <brobecker@adacore.com>
Gerrit-CC: Simon Marchi <simon.marchi@polymtl.ca>
Gerrit-MessageType: newpatchset

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

* [review v10] gdb/mi: Add -max-results parameter to some -symbol-info-* commands
       [not found] <gerrit.1571909344000.I90a28feb55b388fb46461a096c5db08b6b0bd427@gnutoolchain-gerrit.osci.io>
                   ` (14 preceding siblings ...)
  2019-12-02 23:44 ` [review v10] " Andrew Burgess (Code Review)
@ 2019-12-03  0:00 ` Andrew Burgess (Code Review)
  2019-12-03  0:00 ` [review v11] " Andrew Burgess (Code Review)
                   ` (10 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrew Burgess (Code Review) @ 2019-12-03  0:00 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Joel Brobecker

Andrew Burgess has posted comments on this change.

Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/269
......................................................................


Patch Set 10:

> Patch Set 9:
> 
> > Patch Set 9:
> > 
> > All points raised are, I think, addressed in the new restructuring patch.  I changed the max matches to 'unsigned int' instead of 'size_t' - is there a benefit for size_t that I'm missing?  And use UINT_MAX as the default value.  The consequence of this is that there's no truely "unlimited" matching mode any more, but I think with a limit of UINT_MAX this probably isn't a problem.
> 
> Only that "size_t" is guaranteed to be able to hold the largest size an object can have on the machine, so we know it is guaranteed to be large enough to hold the number of results we can possibly return before running out of memory.  In practice, unsigned int is probably large enough too, but there's no such guarantee.
> 
> In any case there is no truly "unlimited" matching mode.  In both cases (using -1 to denote unlimited or using SIZE_MAX as a maximum), the memory of the machine is the limit.

Converted to size_t in latest version.


-- 
Gerrit-Project: binutils-gdb
Gerrit-Branch: master
Gerrit-Change-Id: I90a28feb55b388fb46461a096c5db08b6b0bd427
Gerrit-Change-Number: 269
Gerrit-PatchSet: 10
Gerrit-Owner: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-Reviewer: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-CC: Joel Brobecker <brobecker@adacore.com>
Gerrit-CC: Simon Marchi <simon.marchi@polymtl.ca>
Gerrit-Comment-Date: Mon, 02 Dec 2019 23:59:55 +0000
Gerrit-HasComments: No
Gerrit-Has-Labels: No
Gerrit-MessageType: comment

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

* [review v11] gdb/mi: Add -max-results parameter to some -symbol-info-* commands
       [not found] <gerrit.1571909344000.I90a28feb55b388fb46461a096c5db08b6b0bd427@gnutoolchain-gerrit.osci.io>
                   ` (15 preceding siblings ...)
  2019-12-03  0:00 ` Andrew Burgess (Code Review)
@ 2019-12-03  0:00 ` Andrew Burgess (Code Review)
  2019-12-03  4:12 ` Simon Marchi (Code Review)
                   ` (9 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrew Burgess (Code Review) @ 2019-12-03  0:00 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker, Simon Marchi

Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/269
......................................................................

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

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.

One other thing to note is that the global_symbol_searcher::search by
default returns UINT_MAX results, there's no longer a mechanism to
return an unlimited number of results, though hopefully this will not
be a huge issue.

gdb/ChangeLog:

	* mi/mi-symbol-cmds.c (mi_symbol_info): Take extra parameter, and
	add it into the search spec.
	(parse_max_results_option): New function.
	(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 (global_symbol_searcher::add_matching_symbols): Change
	return type to bool, change result container into a set, and don't
	add new results if we have enough already.
	(global_symbol_searcher::add_matching_msymbols): Change return
	type to bool, and don't add new results if we have enough already.
	(sort_search_symbols_remove_dups): Delete.
	(global_symbol_searcher::search): Early exit from search loop when
	we have enough results.  Use a std::set to collect the results
	from calling add_matching_symbols.
	* symtab.h (global_symbol_searcher) <set_max_seach_results>: New
	member function.
	(global_symbol_searcher) <m_max_search_results>: New member
	variable.
	(global_symbol_searcher) <add_matching_symbols>: Update header
	comment and change return type to bool.
	(global_symbol_searcher) <add_matching_msymbols>: Update header
	comment and change return type to bool.

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
---
M gdb/ChangeLog
M gdb/doc/ChangeLog
M gdb/doc/gdb.texinfo
M gdb/mi/mi-symbol-cmds.c
M gdb/symtab.c
M gdb/symtab.h
M gdb/testsuite/ChangeLog
M gdb/testsuite/gdb.mi/mi-sym-info.exp
8 files changed, 179 insertions(+), 35 deletions(-)



diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 53161f5..4a8cb96 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,32 @@
 2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* mi/mi-symbol-cmds.c (mi_symbol_info): Take extra parameter, and
+	add it into the search spec.
+	(parse_max_results_option): New function.
+	(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 (global_symbol_searcher::add_matching_symbols): Change
+	return type to bool, change result container into a set, and don't
+	add new results if we have enough already.
+	(global_symbol_searcher::add_matching_msymbols): Change return
+	type to bool, and don't add new results if we have enough already.
+	(sort_search_symbols_remove_dups): Delete.
+	(global_symbol_searcher::search): Early exit from search loop when
+	we have enough results.  Use a std::set to collect the results
+	from calling add_matching_symbols.
+	* symtab.h (global_symbol_searcher) <set_max_seach_results>: New
+	member function.
+	(global_symbol_searcher) <m_max_search_results>: New member
+	variable.
+	(global_symbol_searcher) <add_matching_symbols>: Update header
+	comment and change return type to bool.
+	(global_symbol_searcher) <add_matching_msymbols>: Update header
+	comment and change return type to bool.
+
+2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* symtab.c (symbol_search::compare_search_syms): Update header
 	comment.
 	(global_symbol_searcher::is_suitable_msymbol): New function.
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 10e2207..df6026f 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,5 +1,10 @@
 2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* doc/gdb.texinfo (GDB/MI Symbol Query): Add documentation of
+	-max-results to some -symbol-info-* commands.
+
+2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* doc/gdb.texinfo (GDB/MI Symbol Query): Document new MI command
 	-symbol-info-module-functions and -symbol-info-module-variables.
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 6fb7e8a..544e632 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -33962,6 +33962,7 @@
  -symbol-info-functions [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
 @end smallexample
 
 @noindent
@@ -33977,6 +33978,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}.
@@ -34208,6 +34214,8 @@
 
 @smallexample
  -symbol-info-modules [--name @var{name_regexp}]
+                      [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34218,6 +34226,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}.
@@ -34262,6 +34275,8 @@
 
 @smallexample
  -symbol-info-types [--name @var{name_regexp}]
+                    [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34275,6 +34290,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}.
@@ -34322,6 +34342,8 @@
  -symbol-info-variables [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34337,6 +34359,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 6334e39..59e1112 100644
--- a/gdb/mi/mi-symbol-cmds.c
+++ b/gdb/mi/mi-symbol-cmds.c
@@ -111,11 +111,13 @@
 
 static void
 mi_symbol_info (enum search_domain kind, const char *name_regexp,
-		const char *type_regexp, bool exclude_minsyms)
+		const char *type_regexp, bool exclude_minsyms,
+		size_t max_results)
 {
   global_symbol_searcher sym_search (kind, name_regexp);
   sym_search.set_symbol_type_regexp (type_regexp);
   sym_search.set_exclude_minsyms (exclude_minsyms);
+  sym_search.set_max_search_results (max_results);
   std::vector<symbol_search> symbols = sym_search.search ();
   ui_out *uiout = current_uiout;
   int i = 0;
@@ -166,25 +168,42 @@
     }
 }
 
+/* Helper to parse the option text from an -max-results argument and return
+   the parsed value.  If the text can't be parsed then an error is thrown.  */
+
+static size_t
+parse_max_results_option (const char *arg)
+{
+  char *ptr = arg;
+  long long val = strtoll (arg, &ptr, 10);
+  if (arg == ptr || val > SIZE_MAX || val < 0)
+    error (_("invalid value for --max-results argument"));
+  size_t max_results = (size_t) val;
+
+  return max_results;
+}
+
 /* 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)
 {
+  size_t max_results = SIZE_MAX;
   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 }
   };
 
@@ -210,10 +229,13 @@
 	case NAME_REGEXP_OPT:
 	  regexp = oarg;
 	  break;
+	case MAX_RESULTS_OPT:
+	  parse_max_results_option = parse_max_results_option (oarg);
+	  break;
 	}
     }
 
-  mi_symbol_info (kind, regexp, t_regexp, exclude_minsyms);
+  mi_symbol_info (kind, regexp, t_regexp, exclude_minsyms, max_results);
 }
 
 /* Helper for mi_info_module_functions_or_variables.  Display the results
@@ -382,15 +404,17 @@
 void
 mi_cmd_symbol_info_modules (const char *command, char **argv, int argc)
 {
+  size_t max_results = SIZE_MAX;
   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 }
   };
 
@@ -408,10 +432,13 @@
 	case NAME_REGEXP_OPT:
 	  regexp = oarg;
 	  break;
+	case MAX_RESULTS_OPT:
+	  parse_max_results_option = parse_max_results_option (oarg);
+	  break;
 	}
     }
 
-  mi_symbol_info (MODULES_DOMAIN, regexp, nullptr, true);
+  mi_symbol_info (MODULES_DOMAIN, regexp, nullptr, true, max_results);
 }
 
 /* Implement -symbol-info-types command.  */
@@ -419,15 +446,17 @@
 void
 mi_cmd_symbol_info_types (const char *command, char **argv, int argc)
 {
+  size_t max_results = SIZE_MAX;
   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 }
   };
 
@@ -445,10 +474,13 @@
 	case NAME_REGEXP_OPT:
 	  regexp = oarg;
 	  break;
+	case MAX_RESULTS_OPT:
+	  parse_max_results_option = parse_max_results_option (oarg);
+	  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 f3f0bd5..88b5bd8 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4534,12 +4534,12 @@
 
 /* See symtab.h.  */
 
-void
+bool
 global_symbol_searcher::add_matching_symbols
 	(objfile *objfile,
 	 const gdb::optional<compiled_regex> &preg,
 	 const gdb::optional<compiled_regex> &treg,
-	 std::vector<symbol_search> *results) const
+	 std::set<symbol_search> *result_set) const
 {
   enum search_domain kind = m_kind;
 
@@ -4597,17 +4597,26 @@
 			      && SYMBOL_DOMAIN (sym) == MODULE_DOMAIN
 			      && SYMBOL_LINE (sym) != 0))))
 		{
-		  /* Match, insert if not already in the results.  */
-		  results->emplace_back (block, sym);
+		  if (result_set->size () < m_max_search_results)
+		    {
+		      /* Match, insert if not already in the results.  */
+		      symbol_search ss (block, sym);
+		      if (result_set->find (ss) == result_set->end ())
+			result_set->insert (ss);
+		    }
+		  else
+		    return false;
 		}
 	    }
 	}
     }
+
+  return true;
 }
 
 /* See symtab.h.  */
 
-void
+bool
 global_symbol_searcher::add_matching_msymbols
 	(objfile *objfile, const gdb::optional<compiled_regex> &preg,
 	 std::vector<symbol_search> *results) const
@@ -4639,22 +4648,17 @@
 		       VAR_DOMAIN).symbol == NULL)
 		    {
 		      /* Matching msymbol, add it to the results list.  */
-		      results->emplace_back (GLOBAL_BLOCK, msymbol, objfile);
+		      if (results->size () < m_max_search_results)
+			results->emplace_back (GLOBAL_BLOCK, msymbol, objfile);
+		      else
+			return false;
 		    }
 		}
 	    }
 	}
     }
-}
 
-/* Sort the symbols in RESULT and remove duplicates.  */
-
-static void
-sort_search_symbols_remove_dups (std::vector<symbol_search> *result)
-{
-  std::sort (result->begin (), result->end ());
-  result->erase (std::unique (result->begin (), result->end ()),
-		 result->end ());
+  return true;
 }
 
 /* See symtab.h.  */
@@ -4720,20 +4724,24 @@
     }
 
   bool found_msymbol = false;
-  std::vector<symbol_search> result;
+  std::set<symbol_search> result_set;
   for (objfile *objfile : current_program_space->objfiles ())
     {
       /* Expand symtabs within objfile that possibly contain matching
 	 symbols.  */
       found_msymbol |= expand_symtabs (objfile, preg);
 
-      /* Find matching symbols within OBJFILE and add them in to the RESULT
-	 vector.  */
-      add_matching_symbols (objfile, preg, treg, &result);
+      /* Find matching symbols within OBJFILE and add them in to the
+	 RESULT_SET set.  Use a set here so that we can easily detect
+	 duplicates as we go, and can therefore track how many unique
+	 matches we have found so far.  */
+      if (!add_matching_symbols (objfile, preg, treg, &result_set))
+	break;
     }
 
-  if (!result.empty ())
-    sort_search_symbols_remove_dups (&result);
+  /* 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 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
@@ -4745,7 +4753,8 @@
     {
       gdb_assert (m_kind == VARIABLES_DOMAIN || m_kind == FUNCTIONS_DOMAIN);
       for (objfile *objfile : current_program_space->objfiles ())
-	add_matching_msymbols (objfile, preg, &result);
+	if (!add_matching_msymbols (objfile, preg, &result))
+	  break;
     }
 
   return result;
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 41abf1f..e8321d4 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -23,6 +23,7 @@
 #include <array>
 #include <vector>
 #include <string>
+#include <set>
 #include "gdbsupport/gdb_vecs.h"
 #include "gdbtypes.h"
 #include "gdb_obstack.h"
@@ -2092,6 +2093,12 @@
     m_exclude_minsyms = exclude_minsyms;
   }
 
+  /* Set the maximum number of search results to be returned.  */
+  void set_max_search_results (size_t max_search_results)
+  {
+    m_max_search_results = max_search_results;
+  }
+
   /* Search the symbols from all objfiles in the current program space
      looking for matches as defined by the current state of this object.
 
@@ -2125,6 +2132,10 @@
      be included in the results, otherwise they are excluded.  */
   bool m_exclude_minsyms = false;
 
+  /* Maximum number of search results.  We currently impose a hard limit
+     of SIZE_MAX, there is no "unlimited".  */
+  size_t m_max_search_results = SIZE_MAX;
+
   /* Expand symtabs in OBJFILE that match PREG, are of type M_KIND.  Return
      true if any msymbols were seen that we should later consider adding to
      the results list.  */
@@ -2132,15 +2143,23 @@
 		       const gdb::optional<compiled_regex> &preg) const;
 
   /* Add symbols from symtabs in OBJFILE that match PREG, and TREG, and are
-     of type M_KIND, to the results vector RESULTS.  */
-  void add_matching_symbols (objfile *objfile,
+     of type M_KIND, to the results set RESULTS_SET.  Return false if we
+     stop adding results early due to having already found too many results
+     (based on M_MAX_SEARCH_RESULTS limit), otherwise return true.
+     Returning true does not indicate that any results were added, just
+     that we didn't _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
+  bool add_matching_symbols (objfile *objfile,
 			     const gdb::optional<compiled_regex> &preg,
 			     const gdb::optional<compiled_regex> &treg,
-			     std::vector<symbol_search> *results) const;
+			     std::set<symbol_search> *result_set) const;
 
-  /* Add msymbols from OBJFILE that match PREG and M_KIND, to the
-     results vector RESULTS.  */
-  void add_matching_msymbols (objfile *objfile,
+  /* Add msymbols from OBJFILE that match PREG and M_KIND, 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 M_MAX_SEARCH_RESULTS), otherwise return true.  Returning true
+     does not indicate that any results were added, just that we didn't
+     _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
+  bool add_matching_msymbols (objfile *objfile,
 			      const gdb::optional<compiled_regex> &preg,
 			      std::vector<symbol_search> *results) const;
 
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 7fa48e3..765fb84 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,9 @@
 2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* gdb.mi/mi-sym-info.exp: Add tests for -max-results parameter.
+
+2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* gdb.mi/mi-fortran-modules.exp: Add additional tests for
 	-symbol-info-module-functions and -symbol-info-module-variables.
 
diff --git a/gdb/testsuite/gdb.mi/mi-sym-info.exp b/gdb/testsuite/gdb.mi/mi-sym-info.exp
index 33fe865..4a65bd6 100644
--- a/gdb/testsuite/gdb.mi/mi-sym-info.exp
+++ b/gdb/testsuite/gdb.mi/mi-sym-info.exp
@@ -127,3 +127,24 @@
 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"

-- 
Gerrit-Project: binutils-gdb
Gerrit-Branch: master
Gerrit-Change-Id: I90a28feb55b388fb46461a096c5db08b6b0bd427
Gerrit-Change-Number: 269
Gerrit-PatchSet: 11
Gerrit-Owner: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-Reviewer: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-CC: Joel Brobecker <brobecker@adacore.com>
Gerrit-CC: Simon Marchi <simon.marchi@polymtl.ca>
Gerrit-MessageType: newpatchset

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

* [review v11] gdb/mi: Add -max-results parameter to some -symbol-info-* commands
       [not found] <gerrit.1571909344000.I90a28feb55b388fb46461a096c5db08b6b0bd427@gnutoolchain-gerrit.osci.io>
                   ` (16 preceding siblings ...)
  2019-12-03  0:00 ` [review v11] " Andrew Burgess (Code Review)
@ 2019-12-03  4:12 ` Simon Marchi (Code Review)
  2019-12-03 10:25 ` [review v12] " Andrew Burgess (Code Review)
                   ` (8 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Simon Marchi (Code Review) @ 2019-12-03  4:12 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches; +Cc: Joel Brobecker

Simon Marchi has posted comments on this change.

Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/269
......................................................................


Patch Set 11:

(2 comments)

I'm getting a bunch of compilation errors that I am surprised you don't get:

 /home/simark/src/binutils-gdb/gdb/mi/mi-symbol-cmds.c: In function ‘size_t parse_max_results_option(const char*)’:
 /home/simark/src/binutils-gdb/gdb/mi/mi-symbol-cmds.c:177:15: error: invalid conversion from ‘const char*’ to ‘char*’ [-fpermissive]
   177 |   char *ptr = arg;
       |               ^~~
       |               |
       |               const char*
 /home/simark/src/binutils-gdb/gdb/mi/mi-symbol-cmds.c: In function ‘void mi_info_functions_or_variables(search_domain, char**, int)’:
 /home/simark/src/binutils-gdb/gdb/mi/mi-symbol-cmds.c:233:29: error: assignment of function ‘size_t parse_max_results_option(const char*)’
   233 |    parse_max_results_option = parse_max_results_option (oarg);
       |    ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 /home/simark/src/binutils-gdb/gdb/mi/mi-symbol-cmds.c: In function ‘void mi_cmd_symbol_info_modules(const char*, char**, int)’:
 /home/simark/src/binutils-gdb/gdb/mi/mi-symbol-cmds.c:436:29: error: assignment of function ‘size_t parse_max_results_option(const char*)’
   436 |    parse_max_results_option = parse_max_results_option (oarg);
       |    ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 /home/simark/src/binutils-gdb/gdb/mi/mi-symbol-cmds.c: In function ‘void mi_cmd_symbol_info_types(const char*, char**, int)’:
 /home/simark/src/binutils-gdb/gdb/mi/mi-symbol-cmds.c:478:29: error: assignment of function ‘size_t parse_max_results_option(const char*)’
   478 |    parse_max_results_option = parse_max_results_option (oarg);
       |    ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

| --- /dev/null
| +++ /COMMIT_MSG
| @@ -1,0 +17,19 @@ 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.
| +
| +One other thing to note is that the global_symbol_searcher::search by
| +default returns UINT_MAX results, there's no longer a mechanism to

PS11, Line 26:

Since you changed it so use size_t/SIZE_MAX, this should be updated.

| +return an unlimited number of results, though hopefully this will not
| +be a huge issue.
| +
| +gdb/ChangeLog:
| +
| +	* mi/mi-symbol-cmds.c (mi_symbol_info): Take extra parameter, and
| +	add it into the search spec.
| +	(parse_max_results_option): New function.
| +	(mi_info_functions_or_variables): Parse -max-results flag and pass
| --- gdb/symtab.c
| +++ gdb/symtab.c
| @@ -4737,9 +4735,19 @@ global_symbol_searcher::search () const
| +	 RESULT_SET set.  Use a set here so that we can easily detect
| +	 duplicates as we go, and can therefore track how many unique
| +	 matches we have found so far.  */
| +      if (!add_matching_symbols (objfile, preg, treg, &result_set))
| +	break;
| +    }
| +
| +  /* 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 ());

PS11, Line 4744:

Please check to be sure, but I think this would be unnecessary, as an
std::set is already sorted.  Since you create both the set and the
vector of symbol_search without any explicit comparator, I suppose
they will be sorted using the same criterion.

|  
|    /* If there are no debug symbols, then add matching minsyms.  But if the
|       user wants to see symbols matching a type regexp, then never give a
|       minimal symbol, as we assume that a minimal symbol does not have a
|       type.  */
|    if ((found_msymbol || (filenames.empty () && m_kind == VARIABLES_DOMAIN))
|        && !m_exclude_minsyms
|        && !treg.has_value ())
|      {

-- 
Gerrit-Project: binutils-gdb
Gerrit-Branch: master
Gerrit-Change-Id: I90a28feb55b388fb46461a096c5db08b6b0bd427
Gerrit-Change-Number: 269
Gerrit-PatchSet: 11
Gerrit-Owner: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-Reviewer: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-CC: Joel Brobecker <brobecker@adacore.com>
Gerrit-CC: Simon Marchi <simon.marchi@polymtl.ca>
Gerrit-Comment-Date: Tue, 03 Dec 2019 04:11:54 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
Gerrit-MessageType: comment

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

* [review v12] gdb/mi: Add -max-results parameter to some -symbol-info-* commands
       [not found] <gerrit.1571909344000.I90a28feb55b388fb46461a096c5db08b6b0bd427@gnutoolchain-gerrit.osci.io>
                   ` (17 preceding siblings ...)
  2019-12-03  4:12 ` Simon Marchi (Code Review)
@ 2019-12-03 10:25 ` Andrew Burgess (Code Review)
  2019-12-03 10:56 ` [review v13] " Andrew Burgess (Code Review)
                   ` (7 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrew Burgess (Code Review) @ 2019-12-03 10:25 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker, Simon Marchi

Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/269
......................................................................

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

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.

One other thing to note is that the global_symbol_searcher::search by
default returns UINT_MAX results, there's no longer a mechanism to
return an unlimited number of results, though hopefully this will not
be a huge issue.

gdb/ChangeLog:

	* mi/mi-symbol-cmds.c (mi_symbol_info): Take extra parameter, and
	add it into the search spec.
	(parse_max_results_option): New function.
	(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 (global_symbol_searcher::add_matching_symbols): Change
	return type to bool, change result container into a set, and don't
	add new results if we have enough already.
	(global_symbol_searcher::add_matching_msymbols): Change return
	type to bool, and don't add new results if we have enough already.
	(sort_search_symbols_remove_dups): Delete.
	(global_symbol_searcher::search): Early exit from search loop when
	we have enough results.  Use a std::set to collect the results
	from calling add_matching_symbols.
	* symtab.h (global_symbol_searcher) <set_max_seach_results>: New
	member function.
	(global_symbol_searcher) <m_max_search_results>: New member
	variable.
	(global_symbol_searcher) <add_matching_symbols>: Update header
	comment and change return type to bool.
	(global_symbol_searcher) <add_matching_msymbols>: Update header
	comment and change return type to bool.

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
---
M gdb/ChangeLog
M gdb/doc/ChangeLog
M gdb/doc/gdb.texinfo
M gdb/mi/mi-symbol-cmds.c
M gdb/symtab.c
M gdb/symtab.h
M gdb/testsuite/ChangeLog
M gdb/testsuite/gdb.mi/mi-sym-info.exp
8 files changed, 179 insertions(+), 35 deletions(-)



diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 7ada3ea..05ad777 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,32 @@
 2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* mi/mi-symbol-cmds.c (mi_symbol_info): Take extra parameter, and
+	add it into the search spec.
+	(parse_max_results_option): New function.
+	(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 (global_symbol_searcher::add_matching_symbols): Change
+	return type to bool, change result container into a set, and don't
+	add new results if we have enough already.
+	(global_symbol_searcher::add_matching_msymbols): Change return
+	type to bool, and don't add new results if we have enough already.
+	(sort_search_symbols_remove_dups): Delete.
+	(global_symbol_searcher::search): Early exit from search loop when
+	we have enough results.  Use a std::set to collect the results
+	from calling add_matching_symbols.
+	* symtab.h (global_symbol_searcher) <set_max_seach_results>: New
+	member function.
+	(global_symbol_searcher) <m_max_search_results>: New member
+	variable.
+	(global_symbol_searcher) <add_matching_symbols>: Update header
+	comment and change return type to bool.
+	(global_symbol_searcher) <add_matching_msymbols>: Update header
+	comment and change return type to bool.
+
+2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* symtab.c (symbol_search::compare_search_syms): Update header
 	comment.
 	(global_symbol_searcher::is_suitable_msymbol): New function.
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 10e2207..df6026f 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,5 +1,10 @@
 2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* doc/gdb.texinfo (GDB/MI Symbol Query): Add documentation of
+	-max-results to some -symbol-info-* commands.
+
+2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* doc/gdb.texinfo (GDB/MI Symbol Query): Document new MI command
 	-symbol-info-module-functions and -symbol-info-module-variables.
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 6fb7e8a..544e632 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -33962,6 +33962,7 @@
  -symbol-info-functions [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
 @end smallexample
 
 @noindent
@@ -33977,6 +33978,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}.
@@ -34208,6 +34214,8 @@
 
 @smallexample
  -symbol-info-modules [--name @var{name_regexp}]
+                      [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34218,6 +34226,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}.
@@ -34262,6 +34275,8 @@
 
 @smallexample
  -symbol-info-types [--name @var{name_regexp}]
+                    [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34275,6 +34290,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}.
@@ -34322,6 +34342,8 @@
  -symbol-info-variables [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34337,6 +34359,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 2bebd11..fc1452d 100644
--- a/gdb/mi/mi-symbol-cmds.c
+++ b/gdb/mi/mi-symbol-cmds.c
@@ -111,11 +111,13 @@
 
 static void
 mi_symbol_info (enum search_domain kind, const char *name_regexp,
-		const char *type_regexp, bool exclude_minsyms)
+		const char *type_regexp, bool exclude_minsyms,
+		size_t max_results)
 {
   global_symbol_searcher sym_search (kind, name_regexp);
   sym_search.set_symbol_type_regexp (type_regexp);
   sym_search.set_exclude_minsyms (exclude_minsyms);
+  sym_search.set_max_search_results (max_results);
   std::vector<symbol_search> symbols = sym_search.search ();
   ui_out *uiout = current_uiout;
   int i = 0;
@@ -166,25 +168,42 @@
     }
 }
 
+/* Helper to parse the option text from an -max-results argument and return
+   the parsed value.  If the text can't be parsed then an error is thrown.  */
+
+static size_t
+parse_max_results_option (char *arg)
+{
+  char *ptr = arg;
+  long long val = strtoll (arg, &ptr, 10);
+  if (arg == ptr || val > SIZE_MAX || val < 0)
+    error (_("invalid value for --max-results argument"));
+  size_t max_results = (size_t) val;
+
+  return max_results;
+}
+
 /* 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)
 {
+  size_t max_results = SIZE_MAX;
   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 }
   };
 
@@ -210,10 +229,13 @@
 	case NAME_REGEXP_OPT:
 	  regexp = oarg;
 	  break;
+	case MAX_RESULTS_OPT:
+	  max_results = parse_max_results_option (oarg);
+	  break;
 	}
     }
 
-  mi_symbol_info (kind, regexp, t_regexp, exclude_minsyms);
+  mi_symbol_info (kind, regexp, t_regexp, exclude_minsyms, max_results);
 }
 
 /* Type for an iterator over a vector of module_symbol_search results.  */
@@ -384,15 +406,17 @@
 void
 mi_cmd_symbol_info_modules (const char *command, char **argv, int argc)
 {
+  size_t max_results = SIZE_MAX;
   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 }
   };
 
@@ -410,10 +434,13 @@
 	case NAME_REGEXP_OPT:
 	  regexp = oarg;
 	  break;
+	case MAX_RESULTS_OPT:
+	  max_results = parse_max_results_option (oarg);
+	  break;
 	}
     }
 
-  mi_symbol_info (MODULES_DOMAIN, regexp, nullptr, true);
+  mi_symbol_info (MODULES_DOMAIN, regexp, nullptr, true, max_results);
 }
 
 /* Implement -symbol-info-types command.  */
@@ -421,15 +448,17 @@
 void
 mi_cmd_symbol_info_types (const char *command, char **argv, int argc)
 {
+  size_t max_results = SIZE_MAX;
   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 }
   };
 
@@ -447,10 +476,13 @@
 	case NAME_REGEXP_OPT:
 	  regexp = oarg;
 	  break;
+	case MAX_RESULTS_OPT:
+	  max_results = parse_max_results_option (oarg);
+	  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 f3f0bd5..88b5bd8 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4534,12 +4534,12 @@
 
 /* See symtab.h.  */
 
-void
+bool
 global_symbol_searcher::add_matching_symbols
 	(objfile *objfile,
 	 const gdb::optional<compiled_regex> &preg,
 	 const gdb::optional<compiled_regex> &treg,
-	 std::vector<symbol_search> *results) const
+	 std::set<symbol_search> *result_set) const
 {
   enum search_domain kind = m_kind;
 
@@ -4597,17 +4597,26 @@
 			      && SYMBOL_DOMAIN (sym) == MODULE_DOMAIN
 			      && SYMBOL_LINE (sym) != 0))))
 		{
-		  /* Match, insert if not already in the results.  */
-		  results->emplace_back (block, sym);
+		  if (result_set->size () < m_max_search_results)
+		    {
+		      /* Match, insert if not already in the results.  */
+		      symbol_search ss (block, sym);
+		      if (result_set->find (ss) == result_set->end ())
+			result_set->insert (ss);
+		    }
+		  else
+		    return false;
 		}
 	    }
 	}
     }
+
+  return true;
 }
 
 /* See symtab.h.  */
 
-void
+bool
 global_symbol_searcher::add_matching_msymbols
 	(objfile *objfile, const gdb::optional<compiled_regex> &preg,
 	 std::vector<symbol_search> *results) const
@@ -4639,22 +4648,17 @@
 		       VAR_DOMAIN).symbol == NULL)
 		    {
 		      /* Matching msymbol, add it to the results list.  */
-		      results->emplace_back (GLOBAL_BLOCK, msymbol, objfile);
+		      if (results->size () < m_max_search_results)
+			results->emplace_back (GLOBAL_BLOCK, msymbol, objfile);
+		      else
+			return false;
 		    }
 		}
 	    }
 	}
     }
-}
 
-/* Sort the symbols in RESULT and remove duplicates.  */
-
-static void
-sort_search_symbols_remove_dups (std::vector<symbol_search> *result)
-{
-  std::sort (result->begin (), result->end ());
-  result->erase (std::unique (result->begin (), result->end ()),
-		 result->end ());
+  return true;
 }
 
 /* See symtab.h.  */
@@ -4720,20 +4724,24 @@
     }
 
   bool found_msymbol = false;
-  std::vector<symbol_search> result;
+  std::set<symbol_search> result_set;
   for (objfile *objfile : current_program_space->objfiles ())
     {
       /* Expand symtabs within objfile that possibly contain matching
 	 symbols.  */
       found_msymbol |= expand_symtabs (objfile, preg);
 
-      /* Find matching symbols within OBJFILE and add them in to the RESULT
-	 vector.  */
-      add_matching_symbols (objfile, preg, treg, &result);
+      /* Find matching symbols within OBJFILE and add them in to the
+	 RESULT_SET set.  Use a set here so that we can easily detect
+	 duplicates as we go, and can therefore track how many unique
+	 matches we have found so far.  */
+      if (!add_matching_symbols (objfile, preg, treg, &result_set))
+	break;
     }
 
-  if (!result.empty ())
-    sort_search_symbols_remove_dups (&result);
+  /* 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 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
@@ -4745,7 +4753,8 @@
     {
       gdb_assert (m_kind == VARIABLES_DOMAIN || m_kind == FUNCTIONS_DOMAIN);
       for (objfile *objfile : current_program_space->objfiles ())
-	add_matching_msymbols (objfile, preg, &result);
+	if (!add_matching_msymbols (objfile, preg, &result))
+	  break;
     }
 
   return result;
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 41abf1f..e8321d4 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -23,6 +23,7 @@
 #include <array>
 #include <vector>
 #include <string>
+#include <set>
 #include "gdbsupport/gdb_vecs.h"
 #include "gdbtypes.h"
 #include "gdb_obstack.h"
@@ -2092,6 +2093,12 @@
     m_exclude_minsyms = exclude_minsyms;
   }
 
+  /* Set the maximum number of search results to be returned.  */
+  void set_max_search_results (size_t max_search_results)
+  {
+    m_max_search_results = max_search_results;
+  }
+
   /* Search the symbols from all objfiles in the current program space
      looking for matches as defined by the current state of this object.
 
@@ -2125,6 +2132,10 @@
      be included in the results, otherwise they are excluded.  */
   bool m_exclude_minsyms = false;
 
+  /* Maximum number of search results.  We currently impose a hard limit
+     of SIZE_MAX, there is no "unlimited".  */
+  size_t m_max_search_results = SIZE_MAX;
+
   /* Expand symtabs in OBJFILE that match PREG, are of type M_KIND.  Return
      true if any msymbols were seen that we should later consider adding to
      the results list.  */
@@ -2132,15 +2143,23 @@
 		       const gdb::optional<compiled_regex> &preg) const;
 
   /* Add symbols from symtabs in OBJFILE that match PREG, and TREG, and are
-     of type M_KIND, to the results vector RESULTS.  */
-  void add_matching_symbols (objfile *objfile,
+     of type M_KIND, to the results set RESULTS_SET.  Return false if we
+     stop adding results early due to having already found too many results
+     (based on M_MAX_SEARCH_RESULTS limit), otherwise return true.
+     Returning true does not indicate that any results were added, just
+     that we didn't _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
+  bool add_matching_symbols (objfile *objfile,
 			     const gdb::optional<compiled_regex> &preg,
 			     const gdb::optional<compiled_regex> &treg,
-			     std::vector<symbol_search> *results) const;
+			     std::set<symbol_search> *result_set) const;
 
-  /* Add msymbols from OBJFILE that match PREG and M_KIND, to the
-     results vector RESULTS.  */
-  void add_matching_msymbols (objfile *objfile,
+  /* Add msymbols from OBJFILE that match PREG and M_KIND, 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 M_MAX_SEARCH_RESULTS), otherwise return true.  Returning true
+     does not indicate that any results were added, just that we didn't
+     _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
+  bool add_matching_msymbols (objfile *objfile,
 			      const gdb::optional<compiled_regex> &preg,
 			      std::vector<symbol_search> *results) const;
 
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 7fa48e3..765fb84 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,9 @@
 2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* gdb.mi/mi-sym-info.exp: Add tests for -max-results parameter.
+
+2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* gdb.mi/mi-fortran-modules.exp: Add additional tests for
 	-symbol-info-module-functions and -symbol-info-module-variables.
 
diff --git a/gdb/testsuite/gdb.mi/mi-sym-info.exp b/gdb/testsuite/gdb.mi/mi-sym-info.exp
index 33fe865..4a65bd6 100644
--- a/gdb/testsuite/gdb.mi/mi-sym-info.exp
+++ b/gdb/testsuite/gdb.mi/mi-sym-info.exp
@@ -127,3 +127,24 @@
 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"

-- 
Gerrit-Project: binutils-gdb
Gerrit-Branch: master
Gerrit-Change-Id: I90a28feb55b388fb46461a096c5db08b6b0bd427
Gerrit-Change-Number: 269
Gerrit-PatchSet: 12
Gerrit-Owner: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-Reviewer: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-CC: Joel Brobecker <brobecker@adacore.com>
Gerrit-CC: Simon Marchi <simon.marchi@polymtl.ca>
Gerrit-MessageType: newpatchset

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

* [review v13] gdb/mi: Add -max-results parameter to some -symbol-info-* commands
       [not found] <gerrit.1571909344000.I90a28feb55b388fb46461a096c5db08b6b0bd427@gnutoolchain-gerrit.osci.io>
                   ` (18 preceding siblings ...)
  2019-12-03 10:25 ` [review v12] " Andrew Burgess (Code Review)
@ 2019-12-03 10:56 ` Andrew Burgess (Code Review)
  2019-12-03 10:59 ` Andrew Burgess (Code Review)
                   ` (6 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrew Burgess (Code Review) @ 2019-12-03 10:56 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker, Simon Marchi

Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/269
......................................................................

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

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.

One other thing to note is that the global_symbol_searcher::search by
default returns SIZE_MAX results, there's no longer a mechanism to
return an unlimited number of results, though hopefully this will not
be a huge issue.

gdb/ChangeLog:

	* mi/mi-symbol-cmds.c (mi_symbol_info): Take extra parameter, and
	add it into the search spec.
	(parse_max_results_option): New function.
	(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 (global_symbol_searcher::add_matching_symbols): Change
	return type to bool, change result container into a set, and don't
	add new results if we have enough already.
	(global_symbol_searcher::add_matching_msymbols): Change return
	type to bool, and don't add new results if we have enough already.
	(sort_search_symbols_remove_dups): Delete.
	(global_symbol_searcher::search): Early exit from search loop when
	we have enough results.  Use a std::set to collect the results
	from calling add_matching_symbols.
	* symtab.h (global_symbol_searcher) <set_max_seach_results>: New
	member function.
	(global_symbol_searcher) <m_max_search_results>: New member
	variable.
	(global_symbol_searcher) <add_matching_symbols>: Update header
	comment and change return type to bool.
	(global_symbol_searcher) <add_matching_msymbols>: Update header
	comment and change return type to bool.

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
---
M gdb/ChangeLog
M gdb/doc/ChangeLog
M gdb/doc/gdb.texinfo
M gdb/mi/mi-symbol-cmds.c
M gdb/symtab.c
M gdb/symtab.h
M gdb/testsuite/ChangeLog
M gdb/testsuite/gdb.mi/mi-sym-info.exp
8 files changed, 179 insertions(+), 35 deletions(-)



diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 7ada3ea..05ad777 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,32 @@
 2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* mi/mi-symbol-cmds.c (mi_symbol_info): Take extra parameter, and
+	add it into the search spec.
+	(parse_max_results_option): New function.
+	(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 (global_symbol_searcher::add_matching_symbols): Change
+	return type to bool, change result container into a set, and don't
+	add new results if we have enough already.
+	(global_symbol_searcher::add_matching_msymbols): Change return
+	type to bool, and don't add new results if we have enough already.
+	(sort_search_symbols_remove_dups): Delete.
+	(global_symbol_searcher::search): Early exit from search loop when
+	we have enough results.  Use a std::set to collect the results
+	from calling add_matching_symbols.
+	* symtab.h (global_symbol_searcher) <set_max_seach_results>: New
+	member function.
+	(global_symbol_searcher) <m_max_search_results>: New member
+	variable.
+	(global_symbol_searcher) <add_matching_symbols>: Update header
+	comment and change return type to bool.
+	(global_symbol_searcher) <add_matching_msymbols>: Update header
+	comment and change return type to bool.
+
+2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* symtab.c (symbol_search::compare_search_syms): Update header
 	comment.
 	(global_symbol_searcher::is_suitable_msymbol): New function.
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 10e2207..df6026f 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,5 +1,10 @@
 2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* doc/gdb.texinfo (GDB/MI Symbol Query): Add documentation of
+	-max-results to some -symbol-info-* commands.
+
+2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* doc/gdb.texinfo (GDB/MI Symbol Query): Document new MI command
 	-symbol-info-module-functions and -symbol-info-module-variables.
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 6fb7e8a..544e632 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -33962,6 +33962,7 @@
  -symbol-info-functions [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
 @end smallexample
 
 @noindent
@@ -33977,6 +33978,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}.
@@ -34208,6 +34214,8 @@
 
 @smallexample
  -symbol-info-modules [--name @var{name_regexp}]
+                      [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34218,6 +34226,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}.
@@ -34262,6 +34275,8 @@
 
 @smallexample
  -symbol-info-types [--name @var{name_regexp}]
+                    [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34275,6 +34290,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}.
@@ -34322,6 +34342,8 @@
  -symbol-info-variables [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34337,6 +34359,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 2bebd11..fc1452d 100644
--- a/gdb/mi/mi-symbol-cmds.c
+++ b/gdb/mi/mi-symbol-cmds.c
@@ -111,11 +111,13 @@
 
 static void
 mi_symbol_info (enum search_domain kind, const char *name_regexp,
-		const char *type_regexp, bool exclude_minsyms)
+		const char *type_regexp, bool exclude_minsyms,
+		size_t max_results)
 {
   global_symbol_searcher sym_search (kind, name_regexp);
   sym_search.set_symbol_type_regexp (type_regexp);
   sym_search.set_exclude_minsyms (exclude_minsyms);
+  sym_search.set_max_search_results (max_results);
   std::vector<symbol_search> symbols = sym_search.search ();
   ui_out *uiout = current_uiout;
   int i = 0;
@@ -166,25 +168,42 @@
     }
 }
 
+/* Helper to parse the option text from an -max-results argument and return
+   the parsed value.  If the text can't be parsed then an error is thrown.  */
+
+static size_t
+parse_max_results_option (char *arg)
+{
+  char *ptr = arg;
+  long long val = strtoll (arg, &ptr, 10);
+  if (arg == ptr || val > SIZE_MAX || val < 0)
+    error (_("invalid value for --max-results argument"));
+  size_t max_results = (size_t) val;
+
+  return max_results;
+}
+
 /* 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)
 {
+  size_t max_results = SIZE_MAX;
   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 }
   };
 
@@ -210,10 +229,13 @@
 	case NAME_REGEXP_OPT:
 	  regexp = oarg;
 	  break;
+	case MAX_RESULTS_OPT:
+	  max_results = parse_max_results_option (oarg);
+	  break;
 	}
     }
 
-  mi_symbol_info (kind, regexp, t_regexp, exclude_minsyms);
+  mi_symbol_info (kind, regexp, t_regexp, exclude_minsyms, max_results);
 }
 
 /* Type for an iterator over a vector of module_symbol_search results.  */
@@ -384,15 +406,17 @@
 void
 mi_cmd_symbol_info_modules (const char *command, char **argv, int argc)
 {
+  size_t max_results = SIZE_MAX;
   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 }
   };
 
@@ -410,10 +434,13 @@
 	case NAME_REGEXP_OPT:
 	  regexp = oarg;
 	  break;
+	case MAX_RESULTS_OPT:
+	  max_results = parse_max_results_option (oarg);
+	  break;
 	}
     }
 
-  mi_symbol_info (MODULES_DOMAIN, regexp, nullptr, true);
+  mi_symbol_info (MODULES_DOMAIN, regexp, nullptr, true, max_results);
 }
 
 /* Implement -symbol-info-types command.  */
@@ -421,15 +448,17 @@
 void
 mi_cmd_symbol_info_types (const char *command, char **argv, int argc)
 {
+  size_t max_results = SIZE_MAX;
   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 }
   };
 
@@ -447,10 +476,13 @@
 	case NAME_REGEXP_OPT:
 	  regexp = oarg;
 	  break;
+	case MAX_RESULTS_OPT:
+	  max_results = parse_max_results_option (oarg);
+	  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 9dcb559..76989dc 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4534,12 +4534,12 @@
 
 /* See symtab.h.  */
 
-void
+bool
 global_symbol_searcher::add_matching_symbols
 	(objfile *objfile,
 	 const gdb::optional<compiled_regex> &preg,
 	 const gdb::optional<compiled_regex> &treg,
-	 std::vector<symbol_search> *results) const
+	 std::set<symbol_search> *result_set) const
 {
   enum search_domain kind = m_kind;
 
@@ -4597,17 +4597,26 @@
 			      && SYMBOL_DOMAIN (sym) == MODULE_DOMAIN
 			      && SYMBOL_LINE (sym) != 0))))
 		{
-		  /* Matching msymbol, add it to the results list.  */
-		  results->emplace_back (block, sym);
+		  if (result_set->size () < m_max_search_results)
+		    {
+		      /* Match, insert if not already in the results.  */
+		      symbol_search ss (block, sym);
+		      if (result_set->find (ss) == result_set->end ())
+			result_set->insert (ss);
+		    }
+		  else
+		    return false;
 		}
 	    }
 	}
     }
+
+  return true;
 }
 
 /* See symtab.h.  */
 
-void
+bool
 global_symbol_searcher::add_matching_msymbols
 	(objfile *objfile, const gdb::optional<compiled_regex> &preg,
 	 std::vector<symbol_search> *results) const
@@ -4639,22 +4648,17 @@
 		       VAR_DOMAIN).symbol == NULL)
 		    {
 		      /* Matching msymbol, add it to the results list.  */
-		      results->emplace_back (GLOBAL_BLOCK, msymbol, objfile);
+		      if (results->size () < m_max_search_results)
+			results->emplace_back (GLOBAL_BLOCK, msymbol, objfile);
+		      else
+			return false;
 		    }
 		}
 	    }
 	}
     }
-}
 
-/* Sort the symbols in RESULT and remove duplicates.  */
-
-static void
-sort_search_symbols_remove_dups (std::vector<symbol_search> *result)
-{
-  std::sort (result->begin (), result->end ());
-  result->erase (std::unique (result->begin (), result->end ()),
-		 result->end ());
+  return true;
 }
 
 /* See symtab.h.  */
@@ -4720,20 +4724,24 @@
     }
 
   bool found_msymbol = false;
-  std::vector<symbol_search> result;
+  std::set<symbol_search> result_set;
   for (objfile *objfile : current_program_space->objfiles ())
     {
       /* Expand symtabs within objfile that possibly contain matching
 	 symbols.  */
       found_msymbol |= expand_symtabs (objfile, preg);
 
-      /* Find matching symbols within OBJFILE and add them in to the RESULT
-	 vector.  */
-      add_matching_symbols (objfile, preg, treg, &result);
+      /* Find matching symbols within OBJFILE and add them in to the
+	 RESULT_SET set.  Use a set here so that we can easily detect
+	 duplicates as we go, and can therefore track how many unique
+	 matches we have found so far.  */
+      if (!add_matching_symbols (objfile, preg, treg, &result_set))
+	break;
     }
 
-  if (!result.empty ())
-    sort_search_symbols_remove_dups (&result);
+  /* Convert the result set into a sorted result list, as std::set is
+     defined to be sorted then no explicit call to std::sort is needed.  */
+  std::vector<symbol_search> result (result_set.begin (), result_set.end ());
 
   /* If 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
@@ -4745,7 +4753,8 @@
     {
       gdb_assert (m_kind == VARIABLES_DOMAIN || m_kind == FUNCTIONS_DOMAIN);
       for (objfile *objfile : current_program_space->objfiles ())
-	add_matching_msymbols (objfile, preg, &result);
+	if (!add_matching_msymbols (objfile, preg, &result))
+	  break;
     }
 
   return result;
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 41abf1f..e8321d4 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -23,6 +23,7 @@
 #include <array>
 #include <vector>
 #include <string>
+#include <set>
 #include "gdbsupport/gdb_vecs.h"
 #include "gdbtypes.h"
 #include "gdb_obstack.h"
@@ -2092,6 +2093,12 @@
     m_exclude_minsyms = exclude_minsyms;
   }
 
+  /* Set the maximum number of search results to be returned.  */
+  void set_max_search_results (size_t max_search_results)
+  {
+    m_max_search_results = max_search_results;
+  }
+
   /* Search the symbols from all objfiles in the current program space
      looking for matches as defined by the current state of this object.
 
@@ -2125,6 +2132,10 @@
      be included in the results, otherwise they are excluded.  */
   bool m_exclude_minsyms = false;
 
+  /* Maximum number of search results.  We currently impose a hard limit
+     of SIZE_MAX, there is no "unlimited".  */
+  size_t m_max_search_results = SIZE_MAX;
+
   /* Expand symtabs in OBJFILE that match PREG, are of type M_KIND.  Return
      true if any msymbols were seen that we should later consider adding to
      the results list.  */
@@ -2132,15 +2143,23 @@
 		       const gdb::optional<compiled_regex> &preg) const;
 
   /* Add symbols from symtabs in OBJFILE that match PREG, and TREG, and are
-     of type M_KIND, to the results vector RESULTS.  */
-  void add_matching_symbols (objfile *objfile,
+     of type M_KIND, to the results set RESULTS_SET.  Return false if we
+     stop adding results early due to having already found too many results
+     (based on M_MAX_SEARCH_RESULTS limit), otherwise return true.
+     Returning true does not indicate that any results were added, just
+     that we didn't _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
+  bool add_matching_symbols (objfile *objfile,
 			     const gdb::optional<compiled_regex> &preg,
 			     const gdb::optional<compiled_regex> &treg,
-			     std::vector<symbol_search> *results) const;
+			     std::set<symbol_search> *result_set) const;
 
-  /* Add msymbols from OBJFILE that match PREG and M_KIND, to the
-     results vector RESULTS.  */
-  void add_matching_msymbols (objfile *objfile,
+  /* Add msymbols from OBJFILE that match PREG and M_KIND, 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 M_MAX_SEARCH_RESULTS), otherwise return true.  Returning true
+     does not indicate that any results were added, just that we didn't
+     _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
+  bool add_matching_msymbols (objfile *objfile,
 			      const gdb::optional<compiled_regex> &preg,
 			      std::vector<symbol_search> *results) const;
 
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 7fa48e3..765fb84 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,9 @@
 2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* gdb.mi/mi-sym-info.exp: Add tests for -max-results parameter.
+
+2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* gdb.mi/mi-fortran-modules.exp: Add additional tests for
 	-symbol-info-module-functions and -symbol-info-module-variables.
 
diff --git a/gdb/testsuite/gdb.mi/mi-sym-info.exp b/gdb/testsuite/gdb.mi/mi-sym-info.exp
index 33fe865..4a65bd6 100644
--- a/gdb/testsuite/gdb.mi/mi-sym-info.exp
+++ b/gdb/testsuite/gdb.mi/mi-sym-info.exp
@@ -127,3 +127,24 @@
 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"

-- 
Gerrit-Project: binutils-gdb
Gerrit-Branch: master
Gerrit-Change-Id: I90a28feb55b388fb46461a096c5db08b6b0bd427
Gerrit-Change-Number: 269
Gerrit-PatchSet: 13
Gerrit-Owner: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-Reviewer: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-CC: Joel Brobecker <brobecker@adacore.com>
Gerrit-CC: Simon Marchi <simon.marchi@polymtl.ca>
Gerrit-MessageType: newpatchset

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

* [review v13] gdb/mi: Add -max-results parameter to some -symbol-info-* commands
       [not found] <gerrit.1571909344000.I90a28feb55b388fb46461a096c5db08b6b0bd427@gnutoolchain-gerrit.osci.io>
                   ` (19 preceding siblings ...)
  2019-12-03 10:56 ` [review v13] " Andrew Burgess (Code Review)
@ 2019-12-03 10:59 ` Andrew Burgess (Code Review)
  2019-12-03 16:50 ` Simon Marchi (Code Review)
                   ` (5 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrew Burgess (Code Review) @ 2019-12-03 10:59 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Joel Brobecker

Andrew Burgess has posted comments on this change.

Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/269
......................................................................


Patch Set 13:

(2 comments)

> Patch Set 11:
> 
> (2 comments)
> 
> I'm getting a bunch of compilation errors that I am surprised you don't get:
> 
>  /home/simark/src/binutils-gdb/gdb/mi/mi-symbol-cmds.c: In function ‘size_t parse_max_results_option(const char*)’:
>  /home/simark/src/binutils-gdb/gdb/mi/mi-symbol-cmds.c:177:15: error: invalid conversion from ‘const char*’ to ‘char*’ [-fpermissive]
>    177 |   char *ptr = arg;
>        |               ^~~
>        |               |
>        |               const char*
>  /home/simark/src/binutils-gdb/gdb/mi/mi-symbol-cmds.c: In function ‘void mi_info_functions_or_variables(search_domain, char**, int)’:
>  /home/simark/src/binutils-gdb/gdb/mi/mi-symbol-cmds.c:233:29: error: assignment of function ‘size_t parse_max_results_option(const char*)’
>    233 |    parse_max_results_option = parse_max_results_option (oarg);
>        |    ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>  /home/simark/src/binutils-gdb/gdb/mi/mi-symbol-cmds.c: In function ‘void mi_cmd_symbol_info_modules(const char*, char**, int)’:
>  /home/simark/src/binutils-gdb/gdb/mi/mi-symbol-cmds.c:436:29: error: assignment of function ‘size_t parse_max_results_option(const char*)’
>    436 |    parse_max_results_option = parse_max_results_option (oarg);
>        |    ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>  /home/simark/src/binutils-gdb/gdb/mi/mi-symbol-cmds.c: In function ‘void mi_cmd_symbol_info_types(const char*, char**, int)’:
>  /home/simark/src/binutils-gdb/gdb/mi/mi-symbol-cmds.c:478:29: error: assignment of function ‘size_t parse_max_results_option(const char*)’
>    478 |    parse_max_results_option = parse_max_results_option (oarg);
>        |    ~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This is really embarrassing :(  At some point last night I got mixed up between two development versions of GDB I was working on, and started building / testing a completely different version of GDB thinking it was this one.  I'm pretty sure it can only have been for the last ~1 hour of work, but still, I have no excuses and I'm sorry.

I've updated the patch, addressed the compilation issue and the other items you pointed out.  Sorry for wasting your time with the previously bad commits.  I'm sure I tested the right thing this time :)

| --- /dev/null
| +++ /COMMIT_MSG
| @@ -1,0 +17,19 @@ 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.
| +
| +One other thing to note is that the global_symbol_searcher::search by
| +default returns UINT_MAX results, there's no longer a mechanism to

PS11, Line 26:

Done.

| +return an unlimited number of results, though hopefully this will not
| +be a huge issue.
| +
| +gdb/ChangeLog:
| +
| +	* mi/mi-symbol-cmds.c (mi_symbol_info): Take extra parameter, and
| +	add it into the search spec.
| +	(parse_max_results_option): New function.
| +	(mi_info_functions_or_variables): Parse -max-results flag and pass
| --- gdb/symtab.c
| +++ gdb/symtab.c
| @@ -4737,9 +4735,19 @@ global_symbol_searcher::search () const
| +	 RESULT_SET set.  Use a set here so that we can easily detect
| +	 duplicates as we go, and can therefore track how many unique
| +	 matches we have found so far.  */
| +      if (!add_matching_symbols (objfile, preg, treg, &result_set))
| +	break;
| +    }
| +
| +  /* 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 ());

PS11, Line 4744:

You are correct that the standard defines a set to be sorted, but my
understanding was that we did provide a mechanism for sorting the
objects in the set by providing `operator<` (and also `operator==`) on
`struct symbol_search`.  The results certainly always appear to be
sorted as I'd expect - am I misunderstanding something here?

|  
|    /* If there are no debug symbols, then add matching minsyms.  But if the
|       user wants to see symbols matching a type regexp, then never give a
|       minimal symbol, as we assume that a minimal symbol does not have a
|       type.  */
|    if ((found_msymbol || (filenames.empty () && m_kind == VARIABLES_DOMAIN))
|        && !m_exclude_minsyms
|        && !treg.has_value ())
|      {

-- 
Gerrit-Project: binutils-gdb
Gerrit-Branch: master
Gerrit-Change-Id: I90a28feb55b388fb46461a096c5db08b6b0bd427
Gerrit-Change-Number: 269
Gerrit-PatchSet: 13
Gerrit-Owner: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-Reviewer: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-CC: Joel Brobecker <brobecker@adacore.com>
Gerrit-CC: Simon Marchi <simon.marchi@polymtl.ca>
Gerrit-Comment-Date: Tue, 03 Dec 2019 10:59:21 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
Comment-In-Reply-To: Simon Marchi <simon.marchi@polymtl.ca>
Gerrit-MessageType: comment

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

* [review v13] gdb/mi: Add -max-results parameter to some -symbol-info-* commands
       [not found] <gerrit.1571909344000.I90a28feb55b388fb46461a096c5db08b6b0bd427@gnutoolchain-gerrit.osci.io>
                   ` (20 preceding siblings ...)
  2019-12-03 10:59 ` Andrew Burgess (Code Review)
@ 2019-12-03 16:50 ` Simon Marchi (Code Review)
  2019-12-03 21:04 ` [review v14] " Andrew Burgess (Code Review)
                   ` (4 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Simon Marchi (Code Review) @ 2019-12-03 16:50 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches; +Cc: Joel Brobecker

Simon Marchi has posted comments on this change.

Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/269
......................................................................


Patch Set 13:

(3 comments)

> Patch Set 13:
> This is really embarrassing :(  At some point last night I got mixed up between two development versions of GDB I was working on, and started building / testing a completely different version of GDB thinking it was this one.  I'm pretty sure it can only have been for the last ~1 hour of work, but still, I have no excuses and I'm sorry.
> 
> I've updated the patch, addressed the compilation issue and the other items you pointed out.  Sorry for wasting your time with the previously bad commits.  I'm sure I tested the right thing this time :)

No worries, it's just a simple mistake of pushing the wrong commit, it happens.

The only remaining bit is about the code to parse the parameter value.

| --- /dev/null
| +++ /COMMIT_MSG
| @@ -1,0 +17,19 @@ 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.
| +
| +One other thing to note is that the global_symbol_searcher::search by
| +default returns UINT_MAX results, there's no longer a mechanism to

PS11, Line 26:

Done

| +return an unlimited number of results, though hopefully this will not
| +be a huge issue.
| +
| +gdb/ChangeLog:
| +
| +	* mi/mi-symbol-cmds.c (mi_symbol_info): Take extra parameter, and
| +	add it into the search spec.
| +	(parse_max_results_option): New function.
| +	(mi_info_functions_or_variables): Parse -max-results flag and pass
| --- gdb/symtab.c
| +++ gdb/symtab.c
| @@ -4737,9 +4735,19 @@ global_symbol_searcher::search () const
| +	 RESULT_SET set.  Use a set here so that we can easily detect
| +	 duplicates as we go, and can therefore track how many unique
| +	 matches we have found so far.  */
| +      if (!add_matching_symbols (objfile, preg, treg, &result_set))
| +	break;
| +    }
| +
| +  /* 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 ());

PS11, Line 4744:

> You are correct that the standard defines a set to be sorted, but my understanding was that we did provide a mechanism for sorting the objects in the set by providing `operator<` (and also `operator==`) on `struct symbol_search`.  The results certainly always appear to be sorted as I'd expect - am I misunderstanding something here?

Yes, since we don't pass an explicit comparator in the set template,
it uses std::less, which uses the operator< of the element type
(symbol_search).  But then std::sort also sorts elements using
operator<, by default.  So the order of the set will already be the
same as the order of the vector after passing it through std::sort.

|  
|    /* If there are no debug symbols, then add matching minsyms.  But if the
|       user wants to see symbols matching a type regexp, then never give a
|       minimal symbol, as we assume that a minimal symbol does not have a
|       type.  */
|    if ((found_msymbol || (filenames.empty () && m_kind == VARIABLES_DOMAIN))
|        && !m_exclude_minsyms
|        && !treg.has_value ())
|      {
| --- gdb/mi/mi-symbol-cmds.c
| +++ gdb/mi/mi-symbol-cmds.c
| @@ -168,4 +170,19 @@ mi_symbol_info (enum search_domain kind, const char *name_regexp,
|  
| +/* Helper to parse the option text from an -max-results argument and return
| +   the parsed value.  If the text can't be parsed then an error is thrown.  */
| +
| +static size_t
| +parse_max_results_option (char *arg)
| +{
| +  char *ptr = arg;
| +  long long val = strtoll (arg, &ptr, 10);
| +  if (arg == ptr || val > SIZE_MAX || val < 0)

PS13, Line 179:

This lets us pass:

 --max-results 1a

which is interpreted 1.

Did you check elsewhere in the MI code to see if there was already
some helper to do this?  It's not the first time we need to parse an
argument as an integer, so I'm surprised you have to write this from
scratch.

| +    error (_("invalid value for --max-results argument"));
| +  size_t max_results = (size_t) val;
| +
| +  return max_results;
| +}
| +
|  /* Helper for mi_cmd_symbol_info_{functions,variables} - depending on KIND.
|     Processes command line options from ARGV and ARGC.  */
|  

-- 
Gerrit-Project: binutils-gdb
Gerrit-Branch: master
Gerrit-Change-Id: I90a28feb55b388fb46461a096c5db08b6b0bd427
Gerrit-Change-Number: 269
Gerrit-PatchSet: 13
Gerrit-Owner: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-Reviewer: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-CC: Joel Brobecker <brobecker@adacore.com>
Gerrit-CC: Simon Marchi <simon.marchi@polymtl.ca>
Gerrit-Comment-Date: Tue, 03 Dec 2019 16:50:11 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
Comment-In-Reply-To: Andrew Burgess <andrew.burgess@embecosm.com>
Comment-In-Reply-To: Simon Marchi <simon.marchi@polymtl.ca>
Gerrit-MessageType: comment

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

* [review v14] gdb/mi: Add -max-results parameter to some -symbol-info-* commands
       [not found] <gerrit.1571909344000.I90a28feb55b388fb46461a096c5db08b6b0bd427@gnutoolchain-gerrit.osci.io>
                   ` (21 preceding siblings ...)
  2019-12-03 16:50 ` Simon Marchi (Code Review)
@ 2019-12-03 21:04 ` Andrew Burgess (Code Review)
  2019-12-03 21:07 ` Andrew Burgess (Code Review)
                   ` (3 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrew Burgess (Code Review) @ 2019-12-03 21:04 UTC (permalink / raw)
  To: gdb-patches; +Cc: Joel Brobecker, Simon Marchi

Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/269
......................................................................

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

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.

One other thing to note is that the global_symbol_searcher::search by
default returns SIZE_MAX results, there's no longer a mechanism to
return an unlimited number of results, though hopefully this will not
be a huge issue.

gdb/ChangeLog:

	* mi/mi-symbol-cmds.c (mi_symbol_info): Take extra parameter, and
	add it into the search spec.
	(parse_max_results_option): New function.
	(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 (global_symbol_searcher::add_matching_symbols): Change
	return type to bool, change result container into a set, and don't
	add new results if we have enough already.
	(global_symbol_searcher::add_matching_msymbols): Change return
	type to bool, and don't add new results if we have enough already.
	(sort_search_symbols_remove_dups): Delete.
	(global_symbol_searcher::search): Early exit from search loop when
	we have enough results.  Use a std::set to collect the results
	from calling add_matching_symbols.
	* symtab.h (global_symbol_searcher) <set_max_seach_results>: New
	member function.
	(global_symbol_searcher) <m_max_search_results>: New member
	variable.
	(global_symbol_searcher) <add_matching_symbols>: Update header
	comment and change return type to bool.
	(global_symbol_searcher) <add_matching_msymbols>: Update header
	comment and change return type to bool.

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
---
M gdb/ChangeLog
M gdb/doc/ChangeLog
M gdb/doc/gdb.texinfo
M gdb/mi/mi-symbol-cmds.c
M gdb/symtab.c
M gdb/symtab.h
M gdb/testsuite/ChangeLog
M gdb/testsuite/gdb.mi/mi-sym-info.exp
8 files changed, 179 insertions(+), 35 deletions(-)



diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 7ada3ea..05ad777 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,32 @@
 2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* mi/mi-symbol-cmds.c (mi_symbol_info): Take extra parameter, and
+	add it into the search spec.
+	(parse_max_results_option): New function.
+	(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 (global_symbol_searcher::add_matching_symbols): Change
+	return type to bool, change result container into a set, and don't
+	add new results if we have enough already.
+	(global_symbol_searcher::add_matching_msymbols): Change return
+	type to bool, and don't add new results if we have enough already.
+	(sort_search_symbols_remove_dups): Delete.
+	(global_symbol_searcher::search): Early exit from search loop when
+	we have enough results.  Use a std::set to collect the results
+	from calling add_matching_symbols.
+	* symtab.h (global_symbol_searcher) <set_max_seach_results>: New
+	member function.
+	(global_symbol_searcher) <m_max_search_results>: New member
+	variable.
+	(global_symbol_searcher) <add_matching_symbols>: Update header
+	comment and change return type to bool.
+	(global_symbol_searcher) <add_matching_msymbols>: Update header
+	comment and change return type to bool.
+
+2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* symtab.c (symbol_search::compare_search_syms): Update header
 	comment.
 	(global_symbol_searcher::is_suitable_msymbol): New function.
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 10e2207..df6026f 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,5 +1,10 @@
 2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* doc/gdb.texinfo (GDB/MI Symbol Query): Add documentation of
+	-max-results to some -symbol-info-* commands.
+
+2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* doc/gdb.texinfo (GDB/MI Symbol Query): Document new MI command
 	-symbol-info-module-functions and -symbol-info-module-variables.
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 6fb7e8a..544e632 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -33962,6 +33962,7 @@
  -symbol-info-functions [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
 @end smallexample
 
 @noindent
@@ -33977,6 +33978,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}.
@@ -34208,6 +34214,8 @@
 
 @smallexample
  -symbol-info-modules [--name @var{name_regexp}]
+                      [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34218,6 +34226,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}.
@@ -34262,6 +34275,8 @@
 
 @smallexample
  -symbol-info-types [--name @var{name_regexp}]
+                    [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34275,6 +34290,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}.
@@ -34322,6 +34342,8 @@
  -symbol-info-variables [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34337,6 +34359,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 2bebd11..edbafe3 100644
--- a/gdb/mi/mi-symbol-cmds.c
+++ b/gdb/mi/mi-symbol-cmds.c
@@ -111,11 +111,13 @@
 
 static void
 mi_symbol_info (enum search_domain kind, const char *name_regexp,
-		const char *type_regexp, bool exclude_minsyms)
+		const char *type_regexp, bool exclude_minsyms,
+		size_t max_results)
 {
   global_symbol_searcher sym_search (kind, name_regexp);
   sym_search.set_symbol_type_regexp (type_regexp);
   sym_search.set_exclude_minsyms (exclude_minsyms);
+  sym_search.set_max_search_results (max_results);
   std::vector<symbol_search> symbols = sym_search.search ();
   ui_out *uiout = current_uiout;
   int i = 0;
@@ -166,25 +168,42 @@
     }
 }
 
+/* Helper to parse the option text from an -max-results argument and return
+   the parsed value.  If the text can't be parsed then an error is thrown.  */
+
+static size_t
+parse_max_results_option (char *arg)
+{
+  char *ptr = arg;
+  long long val = strtoll (arg, &ptr, 10);
+  if (arg == ptr || *ptr != '\0' || val > SIZE_MAX || val < 0)
+    error (_("invalid value for --max-results argument"));
+  size_t max_results = (size_t) val;
+
+  return max_results;
+}
+
 /* 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)
 {
+  size_t max_results = SIZE_MAX;
   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 }
   };
 
@@ -210,10 +229,13 @@
 	case NAME_REGEXP_OPT:
 	  regexp = oarg;
 	  break;
+	case MAX_RESULTS_OPT:
+	  max_results = parse_max_results_option (oarg);
+	  break;
 	}
     }
 
-  mi_symbol_info (kind, regexp, t_regexp, exclude_minsyms);
+  mi_symbol_info (kind, regexp, t_regexp, exclude_minsyms, max_results);
 }
 
 /* Type for an iterator over a vector of module_symbol_search results.  */
@@ -384,15 +406,17 @@
 void
 mi_cmd_symbol_info_modules (const char *command, char **argv, int argc)
 {
+  size_t max_results = SIZE_MAX;
   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 }
   };
 
@@ -410,10 +434,13 @@
 	case NAME_REGEXP_OPT:
 	  regexp = oarg;
 	  break;
+	case MAX_RESULTS_OPT:
+	  max_results = parse_max_results_option (oarg);
+	  break;
 	}
     }
 
-  mi_symbol_info (MODULES_DOMAIN, regexp, nullptr, true);
+  mi_symbol_info (MODULES_DOMAIN, regexp, nullptr, true, max_results);
 }
 
 /* Implement -symbol-info-types command.  */
@@ -421,15 +448,17 @@
 void
 mi_cmd_symbol_info_types (const char *command, char **argv, int argc)
 {
+  size_t max_results = SIZE_MAX;
   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 }
   };
 
@@ -447,10 +476,13 @@
 	case NAME_REGEXP_OPT:
 	  regexp = oarg;
 	  break;
+	case MAX_RESULTS_OPT:
+	  max_results = parse_max_results_option (oarg);
+	  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 9dcb559..76989dc 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4534,12 +4534,12 @@
 
 /* See symtab.h.  */
 
-void
+bool
 global_symbol_searcher::add_matching_symbols
 	(objfile *objfile,
 	 const gdb::optional<compiled_regex> &preg,
 	 const gdb::optional<compiled_regex> &treg,
-	 std::vector<symbol_search> *results) const
+	 std::set<symbol_search> *result_set) const
 {
   enum search_domain kind = m_kind;
 
@@ -4597,17 +4597,26 @@
 			      && SYMBOL_DOMAIN (sym) == MODULE_DOMAIN
 			      && SYMBOL_LINE (sym) != 0))))
 		{
-		  /* Matching msymbol, add it to the results list.  */
-		  results->emplace_back (block, sym);
+		  if (result_set->size () < m_max_search_results)
+		    {
+		      /* Match, insert if not already in the results.  */
+		      symbol_search ss (block, sym);
+		      if (result_set->find (ss) == result_set->end ())
+			result_set->insert (ss);
+		    }
+		  else
+		    return false;
 		}
 	    }
 	}
     }
+
+  return true;
 }
 
 /* See symtab.h.  */
 
-void
+bool
 global_symbol_searcher::add_matching_msymbols
 	(objfile *objfile, const gdb::optional<compiled_regex> &preg,
 	 std::vector<symbol_search> *results) const
@@ -4639,22 +4648,17 @@
 		       VAR_DOMAIN).symbol == NULL)
 		    {
 		      /* Matching msymbol, add it to the results list.  */
-		      results->emplace_back (GLOBAL_BLOCK, msymbol, objfile);
+		      if (results->size () < m_max_search_results)
+			results->emplace_back (GLOBAL_BLOCK, msymbol, objfile);
+		      else
+			return false;
 		    }
 		}
 	    }
 	}
     }
-}
 
-/* Sort the symbols in RESULT and remove duplicates.  */
-
-static void
-sort_search_symbols_remove_dups (std::vector<symbol_search> *result)
-{
-  std::sort (result->begin (), result->end ());
-  result->erase (std::unique (result->begin (), result->end ()),
-		 result->end ());
+  return true;
 }
 
 /* See symtab.h.  */
@@ -4720,20 +4724,24 @@
     }
 
   bool found_msymbol = false;
-  std::vector<symbol_search> result;
+  std::set<symbol_search> result_set;
   for (objfile *objfile : current_program_space->objfiles ())
     {
       /* Expand symtabs within objfile that possibly contain matching
 	 symbols.  */
       found_msymbol |= expand_symtabs (objfile, preg);
 
-      /* Find matching symbols within OBJFILE and add them in to the RESULT
-	 vector.  */
-      add_matching_symbols (objfile, preg, treg, &result);
+      /* Find matching symbols within OBJFILE and add them in to the
+	 RESULT_SET set.  Use a set here so that we can easily detect
+	 duplicates as we go, and can therefore track how many unique
+	 matches we have found so far.  */
+      if (!add_matching_symbols (objfile, preg, treg, &result_set))
+	break;
     }
 
-  if (!result.empty ())
-    sort_search_symbols_remove_dups (&result);
+  /* Convert the result set into a sorted result list, as std::set is
+     defined to be sorted then no explicit call to std::sort is needed.  */
+  std::vector<symbol_search> result (result_set.begin (), result_set.end ());
 
   /* If 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
@@ -4745,7 +4753,8 @@
     {
       gdb_assert (m_kind == VARIABLES_DOMAIN || m_kind == FUNCTIONS_DOMAIN);
       for (objfile *objfile : current_program_space->objfiles ())
-	add_matching_msymbols (objfile, preg, &result);
+	if (!add_matching_msymbols (objfile, preg, &result))
+	  break;
     }
 
   return result;
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 41abf1f..e8321d4 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -23,6 +23,7 @@
 #include <array>
 #include <vector>
 #include <string>
+#include <set>
 #include "gdbsupport/gdb_vecs.h"
 #include "gdbtypes.h"
 #include "gdb_obstack.h"
@@ -2092,6 +2093,12 @@
     m_exclude_minsyms = exclude_minsyms;
   }
 
+  /* Set the maximum number of search results to be returned.  */
+  void set_max_search_results (size_t max_search_results)
+  {
+    m_max_search_results = max_search_results;
+  }
+
   /* Search the symbols from all objfiles in the current program space
      looking for matches as defined by the current state of this object.
 
@@ -2125,6 +2132,10 @@
      be included in the results, otherwise they are excluded.  */
   bool m_exclude_minsyms = false;
 
+  /* Maximum number of search results.  We currently impose a hard limit
+     of SIZE_MAX, there is no "unlimited".  */
+  size_t m_max_search_results = SIZE_MAX;
+
   /* Expand symtabs in OBJFILE that match PREG, are of type M_KIND.  Return
      true if any msymbols were seen that we should later consider adding to
      the results list.  */
@@ -2132,15 +2143,23 @@
 		       const gdb::optional<compiled_regex> &preg) const;
 
   /* Add symbols from symtabs in OBJFILE that match PREG, and TREG, and are
-     of type M_KIND, to the results vector RESULTS.  */
-  void add_matching_symbols (objfile *objfile,
+     of type M_KIND, to the results set RESULTS_SET.  Return false if we
+     stop adding results early due to having already found too many results
+     (based on M_MAX_SEARCH_RESULTS limit), otherwise return true.
+     Returning true does not indicate that any results were added, just
+     that we didn't _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
+  bool add_matching_symbols (objfile *objfile,
 			     const gdb::optional<compiled_regex> &preg,
 			     const gdb::optional<compiled_regex> &treg,
-			     std::vector<symbol_search> *results) const;
+			     std::set<symbol_search> *result_set) const;
 
-  /* Add msymbols from OBJFILE that match PREG and M_KIND, to the
-     results vector RESULTS.  */
-  void add_matching_msymbols (objfile *objfile,
+  /* Add msymbols from OBJFILE that match PREG and M_KIND, 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 M_MAX_SEARCH_RESULTS), otherwise return true.  Returning true
+     does not indicate that any results were added, just that we didn't
+     _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
+  bool add_matching_msymbols (objfile *objfile,
 			      const gdb::optional<compiled_regex> &preg,
 			      std::vector<symbol_search> *results) const;
 
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 7fa48e3..765fb84 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,9 @@
 2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* gdb.mi/mi-sym-info.exp: Add tests for -max-results parameter.
+
+2019-12-02  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* gdb.mi/mi-fortran-modules.exp: Add additional tests for
 	-symbol-info-module-functions and -symbol-info-module-variables.
 
diff --git a/gdb/testsuite/gdb.mi/mi-sym-info.exp b/gdb/testsuite/gdb.mi/mi-sym-info.exp
index 33fe865..4a65bd6 100644
--- a/gdb/testsuite/gdb.mi/mi-sym-info.exp
+++ b/gdb/testsuite/gdb.mi/mi-sym-info.exp
@@ -127,3 +127,24 @@
 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"

-- 
Gerrit-Project: binutils-gdb
Gerrit-Branch: master
Gerrit-Change-Id: I90a28feb55b388fb46461a096c5db08b6b0bd427
Gerrit-Change-Number: 269
Gerrit-PatchSet: 14
Gerrit-Owner: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-Reviewer: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-CC: Joel Brobecker <brobecker@adacore.com>
Gerrit-CC: Simon Marchi <simon.marchi@polymtl.ca>
Gerrit-MessageType: newpatchset

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

* [review v14] gdb/mi: Add -max-results parameter to some -symbol-info-* commands
       [not found] <gerrit.1571909344000.I90a28feb55b388fb46461a096c5db08b6b0bd427@gnutoolchain-gerrit.osci.io>
                   ` (22 preceding siblings ...)
  2019-12-03 21:04 ` [review v14] " Andrew Burgess (Code Review)
@ 2019-12-03 21:07 ` Andrew Burgess (Code Review)
  2019-12-03 21:12 ` Simon Marchi (Code Review)
                   ` (2 subsequent siblings)
  26 siblings, 0 replies; 28+ messages in thread
From: Andrew Burgess (Code Review) @ 2019-12-03 21:07 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi, Joel Brobecker

Andrew Burgess has posted comments on this change.

Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/269
......................................................................


Patch Set 14:

(1 comment)

| --- gdb/mi/mi-symbol-cmds.c
| +++ gdb/mi/mi-symbol-cmds.c
| @@ -168,4 +170,19 @@ mi_symbol_info (enum search_domain kind, const char *name_regexp,
|  
| +/* Helper to parse the option text from an -max-results argument and return
| +   the parsed value.  If the text can't be parsed then an error is thrown.  */
| +
| +static size_t
| +parse_max_results_option (char *arg)
| +{
| +  char *ptr = arg;
| +  long long val = strtoll (arg, &ptr, 10);
| +  if (arg == ptr || val > SIZE_MAX || val < 0)

PS13, Line 179:

I couldn't find anything.  I checked the manual looking for MI
commands that might take a number or count type argument, the only
examples I could find already either used ato* or strto* functions.  I
couldn't see anything obvious in utils.c or gdbsupport/*.c either -
though I'd be happy to be told I'm missed something!

Anyway, I fixed this issue you pointed out and updated the patch for
now.

| +    error (_("invalid value for --max-results argument"));
| +  size_t max_results = (size_t) val;
| +
| +  return max_results;
| +}
| +
|  /* Helper for mi_cmd_symbol_info_{functions,variables} - depending on KIND.
|     Processes command line options from ARGV and ARGC.  */
|  

-- 
Gerrit-Project: binutils-gdb
Gerrit-Branch: master
Gerrit-Change-Id: I90a28feb55b388fb46461a096c5db08b6b0bd427
Gerrit-Change-Number: 269
Gerrit-PatchSet: 14
Gerrit-Owner: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-Reviewer: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-CC: Joel Brobecker <brobecker@adacore.com>
Gerrit-CC: Simon Marchi <simon.marchi@polymtl.ca>
Gerrit-Comment-Date: Tue, 03 Dec 2019 21:07:48 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: No
Comment-In-Reply-To: Simon Marchi <simon.marchi@polymtl.ca>
Gerrit-MessageType: comment

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

* [review v14] gdb/mi: Add -max-results parameter to some -symbol-info-* commands
       [not found] <gerrit.1571909344000.I90a28feb55b388fb46461a096c5db08b6b0bd427@gnutoolchain-gerrit.osci.io>
                   ` (23 preceding siblings ...)
  2019-12-03 21:07 ` Andrew Burgess (Code Review)
@ 2019-12-03 21:12 ` Simon Marchi (Code Review)
  2019-12-04 10:49 ` [pushed] " Sourceware to Gerrit sync (Code Review)
  2019-12-04 10:49 ` Sourceware to Gerrit sync (Code Review)
  26 siblings, 0 replies; 28+ messages in thread
From: Simon Marchi (Code Review) @ 2019-12-03 21:12 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches; +Cc: Joel Brobecker

Simon Marchi has posted comments on this change.

Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/269
......................................................................


Patch Set 14: Code-Review+2


-- 
Gerrit-Project: binutils-gdb
Gerrit-Branch: master
Gerrit-Change-Id: I90a28feb55b388fb46461a096c5db08b6b0bd427
Gerrit-Change-Number: 269
Gerrit-PatchSet: 14
Gerrit-Owner: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-Reviewer: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-Reviewer: Simon Marchi <simon.marchi@polymtl.ca>
Gerrit-CC: Joel Brobecker <brobecker@adacore.com>
Gerrit-Comment-Date: Tue, 03 Dec 2019 21:12:37 +0000
Gerrit-HasComments: No
Gerrit-Has-Labels: Yes
Gerrit-MessageType: comment

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

* [pushed] gdb/mi: Add -max-results parameter to some -symbol-info-* commands
       [not found] <gerrit.1571909344000.I90a28feb55b388fb46461a096c5db08b6b0bd427@gnutoolchain-gerrit.osci.io>
                   ` (24 preceding siblings ...)
  2019-12-03 21:12 ` Simon Marchi (Code Review)
@ 2019-12-04 10:49 ` Sourceware to Gerrit sync (Code Review)
  2019-12-04 10:49 ` Sourceware to Gerrit sync (Code Review)
  26 siblings, 0 replies; 28+ messages in thread
From: Sourceware to Gerrit sync (Code Review) @ 2019-12-04 10:49 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches; +Cc: Simon Marchi, Joel Brobecker

Sourceware to Gerrit sync has submitted this change.

Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/269
......................................................................

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

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.

One other thing to note is that the global_symbol_searcher::search by
default returns SIZE_MAX results, there's no longer a mechanism to
return an unlimited number of results, though hopefully this will not
be a huge issue.

gdb/ChangeLog:

	* mi/mi-symbol-cmds.c (mi_symbol_info): Take extra parameter, and
	add it into the search spec.
	(parse_max_results_option): New function.
	(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 (global_symbol_searcher::add_matching_symbols): Change
	return type to bool, change result container into a set, and don't
	add new results if we have enough already.
	(global_symbol_searcher::add_matching_msymbols): Change return
	type to bool, and don't add new results if we have enough already.
	(sort_search_symbols_remove_dups): Delete.
	(global_symbol_searcher::search): Early exit from search loop when
	we have enough results.  Use a std::set to collect the results
	from calling add_matching_symbols.
	* symtab.h (global_symbol_searcher) <set_max_seach_results>: New
	member function.
	(global_symbol_searcher) <m_max_search_results>: New member
	variable.
	(global_symbol_searcher) <add_matching_symbols>: Update header
	comment and change return type to bool.
	(global_symbol_searcher) <add_matching_msymbols>: Update header
	comment and change return type to bool.

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
---
M gdb/ChangeLog
M gdb/doc/ChangeLog
M gdb/doc/gdb.texinfo
M gdb/mi/mi-symbol-cmds.c
M gdb/symtab.c
M gdb/symtab.h
M gdb/testsuite/ChangeLog
M gdb/testsuite/gdb.mi/mi-sym-info.exp
8 files changed, 179 insertions(+), 35 deletions(-)


diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 391b23e..aacc0c9 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,32 @@
 2019-12-04  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* mi/mi-symbol-cmds.c (mi_symbol_info): Take extra parameter, and
+	add it into the search spec.
+	(parse_max_results_option): New function.
+	(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 (global_symbol_searcher::add_matching_symbols): Change
+	return type to bool, change result container into a set, and don't
+	add new results if we have enough already.
+	(global_symbol_searcher::add_matching_msymbols): Change return
+	type to bool, and don't add new results if we have enough already.
+	(sort_search_symbols_remove_dups): Delete.
+	(global_symbol_searcher::search): Early exit from search loop when
+	we have enough results.  Use a std::set to collect the results
+	from calling add_matching_symbols.
+	* symtab.h (global_symbol_searcher) <set_max_seach_results>: New
+	member function.
+	(global_symbol_searcher) <m_max_search_results>: New member
+	variable.
+	(global_symbol_searcher) <add_matching_symbols>: Update header
+	comment and change return type to bool.
+	(global_symbol_searcher) <add_matching_msymbols>: Update header
+	comment and change return type to bool.
+
+2019-12-04  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* symtab.c (symbol_search::compare_search_syms): Update header
 	comment.
 	(global_symbol_searcher::is_suitable_msymbol): New function.
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 5b3eab7..9a70de3 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,5 +1,10 @@
 2019-12-04  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* doc/gdb.texinfo (GDB/MI Symbol Query): Add documentation of
+	-max-results to some -symbol-info-* commands.
+
+2019-12-04  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* doc/gdb.texinfo (GDB/MI Symbol Query): Document new MI command
 	-symbol-info-module-functions and -symbol-info-module-variables.
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 6fb7e8a..544e632 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -33962,6 +33962,7 @@
  -symbol-info-functions [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
 @end smallexample
 
 @noindent
@@ -33977,6 +33978,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}.
@@ -34208,6 +34214,8 @@
 
 @smallexample
  -symbol-info-modules [--name @var{name_regexp}]
+                      [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34218,6 +34226,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}.
@@ -34262,6 +34275,8 @@
 
 @smallexample
  -symbol-info-types [--name @var{name_regexp}]
+                    [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34275,6 +34290,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}.
@@ -34322,6 +34342,8 @@
  -symbol-info-variables [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34337,6 +34359,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 2bebd11..edbafe3 100644
--- a/gdb/mi/mi-symbol-cmds.c
+++ b/gdb/mi/mi-symbol-cmds.c
@@ -111,11 +111,13 @@
 
 static void
 mi_symbol_info (enum search_domain kind, const char *name_regexp,
-		const char *type_regexp, bool exclude_minsyms)
+		const char *type_regexp, bool exclude_minsyms,
+		size_t max_results)
 {
   global_symbol_searcher sym_search (kind, name_regexp);
   sym_search.set_symbol_type_regexp (type_regexp);
   sym_search.set_exclude_minsyms (exclude_minsyms);
+  sym_search.set_max_search_results (max_results);
   std::vector<symbol_search> symbols = sym_search.search ();
   ui_out *uiout = current_uiout;
   int i = 0;
@@ -166,25 +168,42 @@
     }
 }
 
+/* Helper to parse the option text from an -max-results argument and return
+   the parsed value.  If the text can't be parsed then an error is thrown.  */
+
+static size_t
+parse_max_results_option (char *arg)
+{
+  char *ptr = arg;
+  long long val = strtoll (arg, &ptr, 10);
+  if (arg == ptr || *ptr != '\0' || val > SIZE_MAX || val < 0)
+    error (_("invalid value for --max-results argument"));
+  size_t max_results = (size_t) val;
+
+  return max_results;
+}
+
 /* 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)
 {
+  size_t max_results = SIZE_MAX;
   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 }
   };
 
@@ -210,10 +229,13 @@
 	case NAME_REGEXP_OPT:
 	  regexp = oarg;
 	  break;
+	case MAX_RESULTS_OPT:
+	  max_results = parse_max_results_option (oarg);
+	  break;
 	}
     }
 
-  mi_symbol_info (kind, regexp, t_regexp, exclude_minsyms);
+  mi_symbol_info (kind, regexp, t_regexp, exclude_minsyms, max_results);
 }
 
 /* Type for an iterator over a vector of module_symbol_search results.  */
@@ -384,15 +406,17 @@
 void
 mi_cmd_symbol_info_modules (const char *command, char **argv, int argc)
 {
+  size_t max_results = SIZE_MAX;
   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 }
   };
 
@@ -410,10 +434,13 @@
 	case NAME_REGEXP_OPT:
 	  regexp = oarg;
 	  break;
+	case MAX_RESULTS_OPT:
+	  max_results = parse_max_results_option (oarg);
+	  break;
 	}
     }
 
-  mi_symbol_info (MODULES_DOMAIN, regexp, nullptr, true);
+  mi_symbol_info (MODULES_DOMAIN, regexp, nullptr, true, max_results);
 }
 
 /* Implement -symbol-info-types command.  */
@@ -421,15 +448,17 @@
 void
 mi_cmd_symbol_info_types (const char *command, char **argv, int argc)
 {
+  size_t max_results = SIZE_MAX;
   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 }
   };
 
@@ -447,10 +476,13 @@
 	case NAME_REGEXP_OPT:
 	  regexp = oarg;
 	  break;
+	case MAX_RESULTS_OPT:
+	  max_results = parse_max_results_option (oarg);
+	  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 d54ff14..6fd1c8c 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4547,12 +4547,12 @@
 
 /* See symtab.h.  */
 
-void
+bool
 global_symbol_searcher::add_matching_symbols
 	(objfile *objfile,
 	 const gdb::optional<compiled_regex> &preg,
 	 const gdb::optional<compiled_regex> &treg,
-	 std::vector<symbol_search> *results) const
+	 std::set<symbol_search> *result_set) const
 {
   enum search_domain kind = m_kind;
 
@@ -4610,17 +4610,26 @@
 			      && SYMBOL_DOMAIN (sym) == MODULE_DOMAIN
 			      && SYMBOL_LINE (sym) != 0))))
 		{
-		  /* Matching msymbol, add it to the results list.  */
-		  results->emplace_back (block, sym);
+		  if (result_set->size () < m_max_search_results)
+		    {
+		      /* Match, insert if not already in the results.  */
+		      symbol_search ss (block, sym);
+		      if (result_set->find (ss) == result_set->end ())
+			result_set->insert (ss);
+		    }
+		  else
+		    return false;
 		}
 	    }
 	}
     }
+
+  return true;
 }
 
 /* See symtab.h.  */
 
-void
+bool
 global_symbol_searcher::add_matching_msymbols
 	(objfile *objfile, const gdb::optional<compiled_regex> &preg,
 	 std::vector<symbol_search> *results) const
@@ -4652,22 +4661,17 @@
 		       VAR_DOMAIN).symbol == NULL)
 		    {
 		      /* Matching msymbol, add it to the results list.  */
-		      results->emplace_back (GLOBAL_BLOCK, msymbol, objfile);
+		      if (results->size () < m_max_search_results)
+			results->emplace_back (GLOBAL_BLOCK, msymbol, objfile);
+		      else
+			return false;
 		    }
 		}
 	    }
 	}
     }
-}
 
-/* Sort the symbols in RESULT and remove duplicates.  */
-
-static void
-sort_search_symbols_remove_dups (std::vector<symbol_search> *result)
-{
-  std::sort (result->begin (), result->end ());
-  result->erase (std::unique (result->begin (), result->end ()),
-		 result->end ());
+  return true;
 }
 
 /* See symtab.h.  */
@@ -4733,20 +4737,24 @@
     }
 
   bool found_msymbol = false;
-  std::vector<symbol_search> result;
+  std::set<symbol_search> result_set;
   for (objfile *objfile : current_program_space->objfiles ())
     {
       /* Expand symtabs within objfile that possibly contain matching
 	 symbols.  */
       found_msymbol |= expand_symtabs (objfile, preg);
 
-      /* Find matching symbols within OBJFILE and add them in to the RESULT
-	 vector.  */
-      add_matching_symbols (objfile, preg, treg, &result);
+      /* Find matching symbols within OBJFILE and add them in to the
+	 RESULT_SET set.  Use a set here so that we can easily detect
+	 duplicates as we go, and can therefore track how many unique
+	 matches we have found so far.  */
+      if (!add_matching_symbols (objfile, preg, treg, &result_set))
+	break;
     }
 
-  if (!result.empty ())
-    sort_search_symbols_remove_dups (&result);
+  /* Convert the result set into a sorted result list, as std::set is
+     defined to be sorted then no explicit call to std::sort is needed.  */
+  std::vector<symbol_search> result (result_set.begin (), result_set.end ());
 
   /* If 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
@@ -4758,7 +4766,8 @@
     {
       gdb_assert (m_kind == VARIABLES_DOMAIN || m_kind == FUNCTIONS_DOMAIN);
       for (objfile *objfile : current_program_space->objfiles ())
-	add_matching_msymbols (objfile, preg, &result);
+	if (!add_matching_msymbols (objfile, preg, &result))
+	  break;
     }
 
   return result;
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 41abf1f..e8321d4 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -23,6 +23,7 @@
 #include <array>
 #include <vector>
 #include <string>
+#include <set>
 #include "gdbsupport/gdb_vecs.h"
 #include "gdbtypes.h"
 #include "gdb_obstack.h"
@@ -2092,6 +2093,12 @@
     m_exclude_minsyms = exclude_minsyms;
   }
 
+  /* Set the maximum number of search results to be returned.  */
+  void set_max_search_results (size_t max_search_results)
+  {
+    m_max_search_results = max_search_results;
+  }
+
   /* Search the symbols from all objfiles in the current program space
      looking for matches as defined by the current state of this object.
 
@@ -2125,6 +2132,10 @@
      be included in the results, otherwise they are excluded.  */
   bool m_exclude_minsyms = false;
 
+  /* Maximum number of search results.  We currently impose a hard limit
+     of SIZE_MAX, there is no "unlimited".  */
+  size_t m_max_search_results = SIZE_MAX;
+
   /* Expand symtabs in OBJFILE that match PREG, are of type M_KIND.  Return
      true if any msymbols were seen that we should later consider adding to
      the results list.  */
@@ -2132,15 +2143,23 @@
 		       const gdb::optional<compiled_regex> &preg) const;
 
   /* Add symbols from symtabs in OBJFILE that match PREG, and TREG, and are
-     of type M_KIND, to the results vector RESULTS.  */
-  void add_matching_symbols (objfile *objfile,
+     of type M_KIND, to the results set RESULTS_SET.  Return false if we
+     stop adding results early due to having already found too many results
+     (based on M_MAX_SEARCH_RESULTS limit), otherwise return true.
+     Returning true does not indicate that any results were added, just
+     that we didn't _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
+  bool add_matching_symbols (objfile *objfile,
 			     const gdb::optional<compiled_regex> &preg,
 			     const gdb::optional<compiled_regex> &treg,
-			     std::vector<symbol_search> *results) const;
+			     std::set<symbol_search> *result_set) const;
 
-  /* Add msymbols from OBJFILE that match PREG and M_KIND, to the
-     results vector RESULTS.  */
-  void add_matching_msymbols (objfile *objfile,
+  /* Add msymbols from OBJFILE that match PREG and M_KIND, 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 M_MAX_SEARCH_RESULTS), otherwise return true.  Returning true
+     does not indicate that any results were added, just that we didn't
+     _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
+  bool add_matching_msymbols (objfile *objfile,
 			      const gdb::optional<compiled_regex> &preg,
 			      std::vector<symbol_search> *results) const;
 
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 9ed64d1..112049f 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,9 @@
 2019-12-04  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* gdb.mi/mi-sym-info.exp: Add tests for -max-results parameter.
+
+2019-12-04  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* gdb.mi/mi-fortran-modules.exp: Add additional tests for
 	-symbol-info-module-functions and -symbol-info-module-variables.
 
diff --git a/gdb/testsuite/gdb.mi/mi-sym-info.exp b/gdb/testsuite/gdb.mi/mi-sym-info.exp
index 33fe865..4a65bd6 100644
--- a/gdb/testsuite/gdb.mi/mi-sym-info.exp
+++ b/gdb/testsuite/gdb.mi/mi-sym-info.exp
@@ -127,3 +127,24 @@
 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"

-- 
Gerrit-Project: binutils-gdb
Gerrit-Branch: master
Gerrit-Change-Id: I90a28feb55b388fb46461a096c5db08b6b0bd427
Gerrit-Change-Number: 269
Gerrit-PatchSet: 15
Gerrit-Owner: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-Reviewer: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-Reviewer: Simon Marchi <simon.marchi@polymtl.ca>
Gerrit-CC: Joel Brobecker <brobecker@adacore.com>
Gerrit-MessageType: merged

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

* [pushed] gdb/mi: Add -max-results parameter to some -symbol-info-* commands
       [not found] <gerrit.1571909344000.I90a28feb55b388fb46461a096c5db08b6b0bd427@gnutoolchain-gerrit.osci.io>
                   ` (25 preceding siblings ...)
  2019-12-04 10:49 ` [pushed] " Sourceware to Gerrit sync (Code Review)
@ 2019-12-04 10:49 ` Sourceware to Gerrit sync (Code Review)
  26 siblings, 0 replies; 28+ messages in thread
From: Sourceware to Gerrit sync (Code Review) @ 2019-12-04 10:49 UTC (permalink / raw)
  To: Andrew Burgess, Simon Marchi, gdb-patches; +Cc: Joel Brobecker

The original change was created by Andrew Burgess.

Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/269
......................................................................

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

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.

One other thing to note is that the global_symbol_searcher::search by
default returns SIZE_MAX results, there's no longer a mechanism to
return an unlimited number of results, though hopefully this will not
be a huge issue.

gdb/ChangeLog:

	* mi/mi-symbol-cmds.c (mi_symbol_info): Take extra parameter, and
	add it into the search spec.
	(parse_max_results_option): New function.
	(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 (global_symbol_searcher::add_matching_symbols): Change
	return type to bool, change result container into a set, and don't
	add new results if we have enough already.
	(global_symbol_searcher::add_matching_msymbols): Change return
	type to bool, and don't add new results if we have enough already.
	(sort_search_symbols_remove_dups): Delete.
	(global_symbol_searcher::search): Early exit from search loop when
	we have enough results.  Use a std::set to collect the results
	from calling add_matching_symbols.
	* symtab.h (global_symbol_searcher) <set_max_seach_results>: New
	member function.
	(global_symbol_searcher) <m_max_search_results>: New member
	variable.
	(global_symbol_searcher) <add_matching_symbols>: Update header
	comment and change return type to bool.
	(global_symbol_searcher) <add_matching_msymbols>: Update header
	comment and change return type to bool.

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
---
M gdb/ChangeLog
M gdb/doc/ChangeLog
M gdb/doc/gdb.texinfo
M gdb/mi/mi-symbol-cmds.c
M gdb/symtab.c
M gdb/symtab.h
M gdb/testsuite/ChangeLog
M gdb/testsuite/gdb.mi/mi-sym-info.exp
8 files changed, 179 insertions(+), 35 deletions(-)



diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 391b23e..aacc0c9 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,32 @@
 2019-12-04  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* mi/mi-symbol-cmds.c (mi_symbol_info): Take extra parameter, and
+	add it into the search spec.
+	(parse_max_results_option): New function.
+	(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 (global_symbol_searcher::add_matching_symbols): Change
+	return type to bool, change result container into a set, and don't
+	add new results if we have enough already.
+	(global_symbol_searcher::add_matching_msymbols): Change return
+	type to bool, and don't add new results if we have enough already.
+	(sort_search_symbols_remove_dups): Delete.
+	(global_symbol_searcher::search): Early exit from search loop when
+	we have enough results.  Use a std::set to collect the results
+	from calling add_matching_symbols.
+	* symtab.h (global_symbol_searcher) <set_max_seach_results>: New
+	member function.
+	(global_symbol_searcher) <m_max_search_results>: New member
+	variable.
+	(global_symbol_searcher) <add_matching_symbols>: Update header
+	comment and change return type to bool.
+	(global_symbol_searcher) <add_matching_msymbols>: Update header
+	comment and change return type to bool.
+
+2019-12-04  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* symtab.c (symbol_search::compare_search_syms): Update header
 	comment.
 	(global_symbol_searcher::is_suitable_msymbol): New function.
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 5b3eab7..9a70de3 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,5 +1,10 @@
 2019-12-04  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* doc/gdb.texinfo (GDB/MI Symbol Query): Add documentation of
+	-max-results to some -symbol-info-* commands.
+
+2019-12-04  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* doc/gdb.texinfo (GDB/MI Symbol Query): Document new MI command
 	-symbol-info-module-functions and -symbol-info-module-variables.
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 6fb7e8a..544e632 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -33962,6 +33962,7 @@
  -symbol-info-functions [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
 @end smallexample
 
 @noindent
@@ -33977,6 +33978,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}.
@@ -34208,6 +34214,8 @@
 
 @smallexample
  -symbol-info-modules [--name @var{name_regexp}]
+                      [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34218,6 +34226,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}.
@@ -34262,6 +34275,8 @@
 
 @smallexample
  -symbol-info-types [--name @var{name_regexp}]
+                    [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34275,6 +34290,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}.
@@ -34322,6 +34342,8 @@
  -symbol-info-variables [--include-nondebug]
                         [--type @var{type_regexp}]
                         [--name @var{name_regexp}]
+                        [--max-results @var{limit}]
+
 @end smallexample
 
 @noindent
@@ -34337,6 +34359,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 2bebd11..edbafe3 100644
--- a/gdb/mi/mi-symbol-cmds.c
+++ b/gdb/mi/mi-symbol-cmds.c
@@ -111,11 +111,13 @@
 
 static void
 mi_symbol_info (enum search_domain kind, const char *name_regexp,
-		const char *type_regexp, bool exclude_minsyms)
+		const char *type_regexp, bool exclude_minsyms,
+		size_t max_results)
 {
   global_symbol_searcher sym_search (kind, name_regexp);
   sym_search.set_symbol_type_regexp (type_regexp);
   sym_search.set_exclude_minsyms (exclude_minsyms);
+  sym_search.set_max_search_results (max_results);
   std::vector<symbol_search> symbols = sym_search.search ();
   ui_out *uiout = current_uiout;
   int i = 0;
@@ -166,25 +168,42 @@
     }
 }
 
+/* Helper to parse the option text from an -max-results argument and return
+   the parsed value.  If the text can't be parsed then an error is thrown.  */
+
+static size_t
+parse_max_results_option (char *arg)
+{
+  char *ptr = arg;
+  long long val = strtoll (arg, &ptr, 10);
+  if (arg == ptr || *ptr != '\0' || val > SIZE_MAX || val < 0)
+    error (_("invalid value for --max-results argument"));
+  size_t max_results = (size_t) val;
+
+  return max_results;
+}
+
 /* 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)
 {
+  size_t max_results = SIZE_MAX;
   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 }
   };
 
@@ -210,10 +229,13 @@
 	case NAME_REGEXP_OPT:
 	  regexp = oarg;
 	  break;
+	case MAX_RESULTS_OPT:
+	  max_results = parse_max_results_option (oarg);
+	  break;
 	}
     }
 
-  mi_symbol_info (kind, regexp, t_regexp, exclude_minsyms);
+  mi_symbol_info (kind, regexp, t_regexp, exclude_minsyms, max_results);
 }
 
 /* Type for an iterator over a vector of module_symbol_search results.  */
@@ -384,15 +406,17 @@
 void
 mi_cmd_symbol_info_modules (const char *command, char **argv, int argc)
 {
+  size_t max_results = SIZE_MAX;
   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 }
   };
 
@@ -410,10 +434,13 @@
 	case NAME_REGEXP_OPT:
 	  regexp = oarg;
 	  break;
+	case MAX_RESULTS_OPT:
+	  max_results = parse_max_results_option (oarg);
+	  break;
 	}
     }
 
-  mi_symbol_info (MODULES_DOMAIN, regexp, nullptr, true);
+  mi_symbol_info (MODULES_DOMAIN, regexp, nullptr, true, max_results);
 }
 
 /* Implement -symbol-info-types command.  */
@@ -421,15 +448,17 @@
 void
 mi_cmd_symbol_info_types (const char *command, char **argv, int argc)
 {
+  size_t max_results = SIZE_MAX;
   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 }
   };
 
@@ -447,10 +476,13 @@
 	case NAME_REGEXP_OPT:
 	  regexp = oarg;
 	  break;
+	case MAX_RESULTS_OPT:
+	  max_results = parse_max_results_option (oarg);
+	  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 d54ff14..6fd1c8c 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4547,12 +4547,12 @@
 
 /* See symtab.h.  */
 
-void
+bool
 global_symbol_searcher::add_matching_symbols
 	(objfile *objfile,
 	 const gdb::optional<compiled_regex> &preg,
 	 const gdb::optional<compiled_regex> &treg,
-	 std::vector<symbol_search> *results) const
+	 std::set<symbol_search> *result_set) const
 {
   enum search_domain kind = m_kind;
 
@@ -4610,17 +4610,26 @@
 			      && SYMBOL_DOMAIN (sym) == MODULE_DOMAIN
 			      && SYMBOL_LINE (sym) != 0))))
 		{
-		  /* Matching msymbol, add it to the results list.  */
-		  results->emplace_back (block, sym);
+		  if (result_set->size () < m_max_search_results)
+		    {
+		      /* Match, insert if not already in the results.  */
+		      symbol_search ss (block, sym);
+		      if (result_set->find (ss) == result_set->end ())
+			result_set->insert (ss);
+		    }
+		  else
+		    return false;
 		}
 	    }
 	}
     }
+
+  return true;
 }
 
 /* See symtab.h.  */
 
-void
+bool
 global_symbol_searcher::add_matching_msymbols
 	(objfile *objfile, const gdb::optional<compiled_regex> &preg,
 	 std::vector<symbol_search> *results) const
@@ -4652,22 +4661,17 @@
 		       VAR_DOMAIN).symbol == NULL)
 		    {
 		      /* Matching msymbol, add it to the results list.  */
-		      results->emplace_back (GLOBAL_BLOCK, msymbol, objfile);
+		      if (results->size () < m_max_search_results)
+			results->emplace_back (GLOBAL_BLOCK, msymbol, objfile);
+		      else
+			return false;
 		    }
 		}
 	    }
 	}
     }
-}
 
-/* Sort the symbols in RESULT and remove duplicates.  */
-
-static void
-sort_search_symbols_remove_dups (std::vector<symbol_search> *result)
-{
-  std::sort (result->begin (), result->end ());
-  result->erase (std::unique (result->begin (), result->end ()),
-		 result->end ());
+  return true;
 }
 
 /* See symtab.h.  */
@@ -4733,20 +4737,24 @@
     }
 
   bool found_msymbol = false;
-  std::vector<symbol_search> result;
+  std::set<symbol_search> result_set;
   for (objfile *objfile : current_program_space->objfiles ())
     {
       /* Expand symtabs within objfile that possibly contain matching
 	 symbols.  */
       found_msymbol |= expand_symtabs (objfile, preg);
 
-      /* Find matching symbols within OBJFILE and add them in to the RESULT
-	 vector.  */
-      add_matching_symbols (objfile, preg, treg, &result);
+      /* Find matching symbols within OBJFILE and add them in to the
+	 RESULT_SET set.  Use a set here so that we can easily detect
+	 duplicates as we go, and can therefore track how many unique
+	 matches we have found so far.  */
+      if (!add_matching_symbols (objfile, preg, treg, &result_set))
+	break;
     }
 
-  if (!result.empty ())
-    sort_search_symbols_remove_dups (&result);
+  /* Convert the result set into a sorted result list, as std::set is
+     defined to be sorted then no explicit call to std::sort is needed.  */
+  std::vector<symbol_search> result (result_set.begin (), result_set.end ());
 
   /* If 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
@@ -4758,7 +4766,8 @@
     {
       gdb_assert (m_kind == VARIABLES_DOMAIN || m_kind == FUNCTIONS_DOMAIN);
       for (objfile *objfile : current_program_space->objfiles ())
-	add_matching_msymbols (objfile, preg, &result);
+	if (!add_matching_msymbols (objfile, preg, &result))
+	  break;
     }
 
   return result;
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 41abf1f..e8321d4 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -23,6 +23,7 @@
 #include <array>
 #include <vector>
 #include <string>
+#include <set>
 #include "gdbsupport/gdb_vecs.h"
 #include "gdbtypes.h"
 #include "gdb_obstack.h"
@@ -2092,6 +2093,12 @@
     m_exclude_minsyms = exclude_minsyms;
   }
 
+  /* Set the maximum number of search results to be returned.  */
+  void set_max_search_results (size_t max_search_results)
+  {
+    m_max_search_results = max_search_results;
+  }
+
   /* Search the symbols from all objfiles in the current program space
      looking for matches as defined by the current state of this object.
 
@@ -2125,6 +2132,10 @@
      be included in the results, otherwise they are excluded.  */
   bool m_exclude_minsyms = false;
 
+  /* Maximum number of search results.  We currently impose a hard limit
+     of SIZE_MAX, there is no "unlimited".  */
+  size_t m_max_search_results = SIZE_MAX;
+
   /* Expand symtabs in OBJFILE that match PREG, are of type M_KIND.  Return
      true if any msymbols were seen that we should later consider adding to
      the results list.  */
@@ -2132,15 +2143,23 @@
 		       const gdb::optional<compiled_regex> &preg) const;
 
   /* Add symbols from symtabs in OBJFILE that match PREG, and TREG, and are
-     of type M_KIND, to the results vector RESULTS.  */
-  void add_matching_symbols (objfile *objfile,
+     of type M_KIND, to the results set RESULTS_SET.  Return false if we
+     stop adding results early due to having already found too many results
+     (based on M_MAX_SEARCH_RESULTS limit), otherwise return true.
+     Returning true does not indicate that any results were added, just
+     that we didn't _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
+  bool add_matching_symbols (objfile *objfile,
 			     const gdb::optional<compiled_regex> &preg,
 			     const gdb::optional<compiled_regex> &treg,
-			     std::vector<symbol_search> *results) const;
+			     std::set<symbol_search> *result_set) const;
 
-  /* Add msymbols from OBJFILE that match PREG and M_KIND, to the
-     results vector RESULTS.  */
-  void add_matching_msymbols (objfile *objfile,
+  /* Add msymbols from OBJFILE that match PREG and M_KIND, 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 M_MAX_SEARCH_RESULTS), otherwise return true.  Returning true
+     does not indicate that any results were added, just that we didn't
+     _not_ add a result due to reaching MAX_SEARCH_RESULTS.  */
+  bool add_matching_msymbols (objfile *objfile,
 			      const gdb::optional<compiled_regex> &preg,
 			      std::vector<symbol_search> *results) const;
 
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 9ed64d1..112049f 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,9 @@
 2019-12-04  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* gdb.mi/mi-sym-info.exp: Add tests for -max-results parameter.
+
+2019-12-04  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* gdb.mi/mi-fortran-modules.exp: Add additional tests for
 	-symbol-info-module-functions and -symbol-info-module-variables.
 
diff --git a/gdb/testsuite/gdb.mi/mi-sym-info.exp b/gdb/testsuite/gdb.mi/mi-sym-info.exp
index 33fe865..4a65bd6 100644
--- a/gdb/testsuite/gdb.mi/mi-sym-info.exp
+++ b/gdb/testsuite/gdb.mi/mi-sym-info.exp
@@ -127,3 +127,24 @@
 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"

-- 
Gerrit-Project: binutils-gdb
Gerrit-Branch: master
Gerrit-Change-Id: I90a28feb55b388fb46461a096c5db08b6b0bd427
Gerrit-Change-Number: 269
Gerrit-PatchSet: 15
Gerrit-Owner: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-Reviewer: Andrew Burgess <andrew.burgess@embecosm.com>
Gerrit-Reviewer: Simon Marchi <simon.marchi@polymtl.ca>
Gerrit-CC: Joel Brobecker <brobecker@adacore.com>
Gerrit-MessageType: newpatchset

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

end of thread, other threads:[~2019-12-04 10:49 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <gerrit.1571909344000.I90a28feb55b388fb46461a096c5db08b6b0bd427@gnutoolchain-gerrit.osci.io>
2019-11-01  1:35 ` [review v2] gdb/mi: Add -max-results parameter to some -symbol-info-* commands Andrew Burgess (Code Review)
2019-11-08  0:50 ` [review v3] " Andrew Burgess (Code Review)
2019-11-08 10:06   ` Eli Zaretskii
2019-11-22 16:42 ` [review v4] " Andrew Burgess (Code Review)
2019-11-22 17:33 ` [review v5] " Andrew Burgess (Code Review)
2019-11-26 23:26 ` [review v6] " Andrew Burgess (Code Review)
2019-11-26 23:40 ` [review v7] " Andrew Burgess (Code Review)
2019-11-27  5:31 ` Simon Marchi (Code Review)
2019-11-27 14:19 ` [review v8] " Andrew Burgess (Code Review)
2019-11-27 14:21 ` Andrew Burgess (Code Review)
2019-12-02 17:57 ` Andrew Burgess (Code Review)
2019-12-02 18:40 ` Simon Marchi (Code Review)
2019-12-02 19:15 ` [review v9] " Andrew Burgess (Code Review)
2019-12-02 19:18 ` Andrew Burgess (Code Review)
2019-12-02 19:37 ` Simon Marchi (Code Review)
2019-12-02 23:44 ` [review v10] " Andrew Burgess (Code Review)
2019-12-03  0:00 ` Andrew Burgess (Code Review)
2019-12-03  0:00 ` [review v11] " Andrew Burgess (Code Review)
2019-12-03  4:12 ` Simon Marchi (Code Review)
2019-12-03 10:25 ` [review v12] " Andrew Burgess (Code Review)
2019-12-03 10:56 ` [review v13] " Andrew Burgess (Code Review)
2019-12-03 10:59 ` Andrew Burgess (Code Review)
2019-12-03 16:50 ` Simon Marchi (Code Review)
2019-12-03 21:04 ` [review v14] " Andrew Burgess (Code Review)
2019-12-03 21:07 ` Andrew Burgess (Code Review)
2019-12-03 21:12 ` Simon Marchi (Code Review)
2019-12-04 10:49 ` [pushed] " Sourceware to Gerrit sync (Code Review)
2019-12-04 10:49 ` Sourceware to Gerrit sync (Code Review)

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).