diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 391b23e9e3..aacc0c9b16 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,30 @@ +2019-12-04 Andrew Burgess + + * 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) : New + member function. + (global_symbol_searcher) : New member + variable. + (global_symbol_searcher) : Update header + comment and change return type to bool. + (global_symbol_searcher) : Update header + comment and change return type to bool. + 2019-12-04 Andrew Burgess * symtab.c (symbol_search::compare_search_syms): Update header diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 5b3eab7d73..9a70de350c 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,8 @@ +2019-12-04 Andrew Burgess + + * doc/gdb.texinfo (GDB/MI Symbol Query): Add documentation of + -max-results to some -symbol-info-* commands. + 2019-12-04 Andrew Burgess * doc/gdb.texinfo (GDB/MI Symbol Query): Document new MI command diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 6fb7e8ab7e..544e632a46 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -33962,6 +33962,7 @@ N.A. -symbol-info-functions [--include-nondebug] [--type @var{type_regexp}] [--name @var{name_regexp}] + [--max-results @var{limit}] @end smallexample @noindent @@ -33977,6 +33978,11 @@ The options @code{--type} and @code{--name} allow the symbols returned to be filtered based on either the name of the function, or the type signature of the function. +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 @@ The corresponding @value{GDBN} command is @samp{info module variables}. @smallexample -symbol-info-modules [--name @var{name_regexp}] + [--max-results @var{limit}] + @end smallexample @noindent @@ -34218,6 +34226,11 @@ which each modules is defined. 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 @@ The corresponding @value{GDBN} command is @samp{info modules}. @smallexample -symbol-info-types [--name @var{name_regexp}] + [--max-results @var{limit}] + @end smallexample @noindent @@ -34275,6 +34290,11 @@ line number. 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 @@ The corresponding @value{GDBN} command is @samp{info types}. -symbol-info-variables [--include-nondebug] [--type @var{type_regexp}] [--name @var{name_regexp}] + [--max-results @var{limit}] + @end smallexample @noindent @@ -34337,6 +34359,11 @@ The options @code{--type} and @code{--name} allow the symbols returned to be filtered based on either the name of the variable, or the type of the variable. +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 2bebd11f79..edbafe3944 100644 --- a/gdb/mi/mi-symbol-cmds.c +++ b/gdb/mi/mi-symbol-cmds.c @@ -111,11 +111,13 @@ output_nondebug_symbol (ui_out *uiout, 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 symbols = sym_search.search (); ui_out *uiout = current_uiout; int i = 0; @@ -166,25 +168,42 @@ 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 || *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 @@ mi_info_functions_or_variables (enum search_domain kind, char **argv, int argc) 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 @@ mi_cmd_symbol_info_module_variables (const char *command, char **argv, 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 @@ mi_cmd_symbol_info_modules (const char *command, char **argv, int argc) 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 @@ mi_cmd_symbol_info_modules (const char *command, char **argv, int argc) void mi_cmd_symbol_info_types (const char *command, char **argv, int argc) { + 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 @@ mi_cmd_symbol_info_types (const char *command, char **argv, int argc) 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 d54ff14443..6fd1c8c4bc 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -4547,12 +4547,12 @@ global_symbol_searcher::expand_symtabs /* See symtab.h. */ -void +bool global_symbol_searcher::add_matching_symbols (objfile *objfile, const gdb::optional &preg, const gdb::optional &treg, - std::vector *results) const + std::set *result_set) const { enum search_domain kind = m_kind; @@ -4610,17 +4610,26 @@ global_symbol_searcher::add_matching_symbols && 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 &preg, std::vector *results) const @@ -4652,22 +4661,17 @@ global_symbol_searcher::add_matching_msymbols 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 *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 @@ global_symbol_searcher::search () const } bool found_msymbol = false; - std::vector result; + std::set 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 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 @@ global_symbol_searcher::search () const { 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 41abf1f38f..e8321d4bb8 100644 --- a/gdb/symtab.h +++ b/gdb/symtab.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "gdbsupport/gdb_vecs.h" #include "gdbtypes.h" #include "gdb_obstack.h" @@ -2092,6 +2093,12 @@ public: 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 @@ private: 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 @@ private: const gdb::optional &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 &preg, const gdb::optional &treg, - std::vector *results) const; + std::set *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 &preg, std::vector *results) const; diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 9ed64d1d4c..112049f2ed 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2019-12-04 Andrew Burgess + + * gdb.mi/mi-sym-info.exp: Add tests for -max-results parameter. + 2019-12-04 Andrew Burgess * gdb.mi/mi-fortran-modules.exp: Add additional tests for diff --git a/gdb/testsuite/gdb.mi/mi-sym-info.exp b/gdb/testsuite/gdb.mi/mi-sym-info.exp index 33fe865781..4a65bd6ee5 100644 --- a/gdb/testsuite/gdb.mi/mi-sym-info.exp +++ b/gdb/testsuite/gdb.mi/mi-sym-info.exp @@ -127,3 +127,24 @@ set lineno2 [gdb_get_line_number "typedef int another_int_t;" ${srcfile2}] mi_gdb_test "120-symbol-info-types --name _int_" \ "120\\^done,symbols=\{debug=\\\[\{filename=\"\[^\"\]+$srcfile\",fullname=\"\[^\"\]+$srcfile\",symbols=\\\[\{line=\"27\",name=\"my_int_t\"\}\\\]\},\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"23\",name=\"another_int_t\"\}\\\]\}\\\]\}" \ "List all types matching _int_" + +# Test the --max-results parameter. +mi_gdb_test "121-symbol-info-functions --max-results 0" \ + "121\\^done,symbols=\{\}" \ + "-symbol-info-functions --max-results 0" + +mi_gdb_test "122-symbol-info-functions --max-results 1" \ + "122\\^done,symbols=\{debug=\\\[\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"39\",name=\"f3\",type=\"int \\(another_int_t\\)\",description=\"int f3\\(another_int_t\\);\"\}\\\]\}\\\]\}" \ + "-symbol-info-functions --max-results 1" + +mi_gdb_test "123-symbol-info-functions --max-results 2" \ + "123\\^done,symbols=\{debug=\\\[\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"33\",name=\"f2\",type=\"float \\(another_float_t\\)\",description=\"float f2\\(another_float_t\\);\"\},\{line=\"39\",name=\"f3\",type=\"int \\(another_int_t\\)\",description=\"int f3\\(another_int_t\\);\"\}\\\]\}\\\]\}" \ + "-symbol-info-functions --max-results 2" + +mi_gdb_test "124-symbol-info-variables --max-results 3" \ + "124\\^done,symbols=\{debug=\\\[\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"21\",name=\"global_f2\",type=\"int\",description=\"int global_f2;\"\},\{line=\"20\",name=\"global_i2\",type=\"int\",description=\"int global_i2;\"\},\{line=\"19\",name=\"global_f1\",type=\"float\",description=\"static float global_f1;\"\}\\\]\}\\\]\}" \ + "-symbol-info-variables --max-results 3" + +mi_gdb_test "125-symbol-info-types --max-results 4" \ + "125\\^done,symbols=\{debug=\\\[\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"24\",name=\"another_float_t\"\},\{line=\"23\",name=\"another_int_t\"\},\{name=\"float\"\},\{name=\"int\"\}\\\]\}\\\]\}" \ + "-symbol-info-types --max-results 4"