[review v4] gdb/mi: Add -max-results parameter to some -symbol-info-* commands

Andrew Burgess (Code Review)
2019-11-22T16:42:25Z

(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