From patchwork Wed Oct 16 23:28:04 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 35074 Received: (qmail 99520 invoked by alias); 16 Oct 2019 23:28:30 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 99462 invoked by uid 89); 16 Oct 2019 23:28:29 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-23.2 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_STOCKGEN, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.1 spammy= X-HELO: mail-wm1-f42.google.com Received: from mail-wm1-f42.google.com (HELO mail-wm1-f42.google.com) (209.85.128.42) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 16 Oct 2019 23:28:23 +0000 Received: by mail-wm1-f42.google.com with SMTP id i16so531346wmd.3 for ; Wed, 16 Oct 2019 16:28:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :in-reply-to:references; bh=itpE4TnuDEMSwIS+hJA0jPl+cpX89kb3OkTvSYlGB9U=; b=IUkjhvWRO1TVXYB273SuVMMMW+Qm30TKik2sKIQN+TYuwAYnvq58EPIy2vuP4lInK6 yil2vFwagbjTXP7SD6/LLGb72/xWu5iNombWSIXYbb67pS28SSPh6qE4SqqXb2L/lkQI NDz65U+58MCxLBGRPX0fE92IunPtCUaWSMvKsnRF+18sFHIjIA9+JORNOwA9k4NtmU48 AzXGKErpdd8WvC56AneiMoo2FqIszCDPoOrH3nkyNtAC+wvFNwAvaZwhBHV+fspxr0f0 m1dwxHipGgLSSwbSJTdx6wlq/8sUQRQiL7Y0XLdPZDK/TjP52Yo9z1YstmPRaEYYMzXB 9CEA== Return-Path: Received: from localhost (host86-128-12-122.range86-128.btcentralplus.com. [86.128.12.122]) by smtp.gmail.com with ESMTPSA id g4sm330394wrw.9.2019.10.16.16.28.19 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Wed, 16 Oct 2019 16:28:19 -0700 (PDT) From: Andrew Burgess To: gdb-patches Cc: Andrew Burgess Subject: [PATCHv3 9/9] gdb/mi: Add -max-results parameter to some -symbol-info-* commands Date: Thu, 17 Oct 2019 00:28:04 +0100 Message-Id: <5dcbdcb925b5ddc1f6b774ea1bc384b71d384073.1571268432.git.andrew.burgess@embecosm.com> In-Reply-To: References: In-Reply-To: References: X-IsSubscribed: yes Adds a new parameter -max-results to -symbol-info-functions, -symbol-info-variables, -symbol-info-types, and -symbol-info-modules. This parameter limits the number of results returned. This change still leaves -symbol-info-module-functions and -symbol-info-module-variables always returning all results, fixing these commands is slightly harder. There's currently no mechanism for the user of these commands to know if the result list has been truncated if you get back the maximum number of results, so if there are exactly 10 functions and you call '-symbol-info-functions --max-results 10' the reply would appear no different than if you had 20 functions and called with a max of 10. Right now, if you get back the maximum then you should assume that there might be more results available. gdb/ChangeLog: * mi/mi-symbol-cmds.c (mi_symbol_info): Take extra parameter, and add it into the search spec. (mi_info_functions_or_variables): Parse -max-results flag and pass it to mi_symbol_info. (mi_cmd_symbol_info_modules): Likewise. (mi_cmd_symbol_info_types): Likewise. * symtab.c (symbol_search::compare_search_syms): Update header comment. (search_symbols_is_suitable_msymbol): New function. (search_symbols_expand_symtabs): New function. (search_symbols_add_matching_symbols): New function. (search_symbols_add_matching_msymbols): New function. (search_symbols): Move most of the content into the new functions above, and call them as needed. * symtab.h (struct search_symbols_spec) : New member variable. gdb/doc/ChangeLog: * doc/gdb.texinfo (GDB/MI Symbol Query): Add documentation of -max-results to some -symbol-info-* commands. gdb/testsuite/ChangeLog: * gdb.mi/mi-sym-info.exp: Add tests for -max-results parameter. Change-Id: I90a28feb55b388fb46461a096c5db08b6b0bd427 --- gdb/ChangeLog | 19 ++ gdb/doc/ChangeLog | 5 + gdb/doc/gdb.texinfo | 27 ++ gdb/mi/mi-symbol-cmds.c | 49 +++- gdb/symtab.c | 492 ++++++++++++++++++++--------------- gdb/symtab.h | 4 + gdb/testsuite/ChangeLog | 4 + gdb/testsuite/gdb.mi/mi-sym-info.exp | 25 ++ 8 files changed, 405 insertions(+), 220 deletions(-) diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 4404c05e225..e40f581e5fe 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -33755,6 +33755,7 @@ -symbol-info-functions [--include-nondebug] [--type @var{type_regexp}] [--name @var{name_regexp}] + [--max-results @var{limit}] @end smallexample @noindent @@ -33770,6 +33771,11 @@ to be filtered based on either the name of the function, or the type signature of the function. +The option @code{--max-results} restricts the command to return no +more than @var{limit} results. If exactly @var{limit} results are +returned then there might be additional results available if a higher +limit is used. + @subsubheading @value{GDBN} Command The corresponding @value{GDBN} command is @samp{info functions}. @@ -34001,6 +34007,8 @@ @smallexample -symbol-info-modules [--name @var{name_regexp}] + [--max-results @var{limit}] + @end smallexample @noindent @@ -34011,6 +34019,11 @@ The option @code{--name} allows the modules returned to be filtered based the name of the module. +The option @code{--max-results} restricts the command to return no +more than @var{limit} results. If exactly @var{limit} results are +returned then there might be additional results available if a higher +limit is used. + @subsubheading @value{GDBN} Command The corresponding @value{GDBN} command is @samp{info modules}. @@ -34055,6 +34068,8 @@ @smallexample -symbol-info-types [--name @var{name_regexp}] + [--max-results @var{limit}] + @end smallexample @noindent @@ -34068,6 +34083,11 @@ The option @code{--name} allows the list of types returned to be filtered by name. +The option @code{--max-results} restricts the command to return no +more than @var{limit} results. If exactly @var{limit} results are +returned then there might be additional results available if a higher +limit is used. + @subsubheading @value{GDBN} Command The corresponding @value{GDBN} command is @samp{info types}. @@ -34115,6 +34135,8 @@ -symbol-info-variables [--include-nondebug] [--type @var{type_regexp}] [--name @var{name_regexp}] + [--max-results @var{limit}] + @end smallexample @noindent @@ -34130,6 +34152,11 @@ to be filtered based on either the name of the variable, or the type of the variable. +The option @code{--max-results} restricts the command to return no +more than @var{limit} results. If exactly @var{limit} results are +returned then there might be additional results available if a higher +limit is used. + @subsubheading @value{GDBN} Command The corresponding @value{GDBN} command is @samp{info variables}. diff --git a/gdb/mi/mi-symbol-cmds.c b/gdb/mi/mi-symbol-cmds.c index 64f24f6bae5..4aa95909816 100644 --- a/gdb/mi/mi-symbol-cmds.c +++ b/gdb/mi/mi-symbol-cmds.c @@ -100,12 +100,14 @@ mi_info_one_symbol_details (enum search_domain kind, static void mi_symbol_info (enum search_domain kind, const char *regexp, - const char *t_regexp, bool exclude_minsyms) + const char *t_regexp, bool exclude_minsyms, + int max_results) { struct ui_out *uiout = current_uiout; /* Must make sure that if we're interrupted, symbols gets freed. */ search_symbols_spec spec (kind, regexp, t_regexp, exclude_minsyms); + spec.max_search_results = max_results; std::vector symbols = search_symbols (spec); /* The outer container for all the matched symbols. */ @@ -186,19 +188,21 @@ mi_symbol_info (enum search_domain kind, const char *regexp, static void mi_info_functions_or_variables (enum search_domain kind, char **argv, int argc) { + int max_results = -1; /* -1 for unlimited. */ const char *regexp = nullptr; const char *t_regexp = nullptr; bool exclude_minsyms = true; enum opt { - INCLUDE_NONDEBUG_OPT, TYPE_REGEXP_OPT, NAME_REGEXP_OPT + INCLUDE_NONDEBUG_OPT, TYPE_REGEXP_OPT, NAME_REGEXP_OPT, MAX_RESULTS_OPT }; static const struct mi_opt opts[] = { {"-include-nondebug" , INCLUDE_NONDEBUG_OPT, 0}, {"-type", TYPE_REGEXP_OPT, 1}, {"-name", NAME_REGEXP_OPT, 1}, + {"-max-results", MAX_RESULTS_OPT, 1}, { 0, 0, 0 } }; @@ -224,10 +228,19 @@ mi_info_functions_or_variables (enum search_domain kind, char **argv, int argc) case NAME_REGEXP_OPT: regexp = oarg; break; + case MAX_RESULTS_OPT: + { + char *eptr = oarg; + long val = strtol (oarg, &eptr, 10); + if (oarg == eptr || val > INT_MAX || val < 0) + error (_("invalid value for --max-results argument")); + max_results = (int) val; + } + break; } } - mi_symbol_info (kind, regexp, t_regexp, exclude_minsyms); + mi_symbol_info (kind, regexp, t_regexp, exclude_minsyms, max_results); } /* Core of -symbol-info-module-functions and -symbol-info-module-variables. @@ -361,15 +374,17 @@ mi_cmd_symbol_info_module_variables (const char *command, char **argv, void mi_cmd_symbol_info_modules (const char *command, char **argv, int argc) { + int max_results = -1; /* -1 for unlimited. */ const char *regexp = nullptr; enum opt { - NAME_REGEXP_OPT + NAME_REGEXP_OPT, MAX_RESULTS_OPT }; static const struct mi_opt opts[] = { {"-name", NAME_REGEXP_OPT, 1}, + {"-max-results", MAX_RESULTS_OPT, 1}, { 0, 0, 0 } }; @@ -387,10 +402,19 @@ mi_cmd_symbol_info_modules (const char *command, char **argv, int argc) case NAME_REGEXP_OPT: regexp = oarg; break; + case MAX_RESULTS_OPT: + { + char *eptr = oarg; + long val = strtol (oarg, &eptr, 10); + if (oarg == eptr || val > INT_MAX || val < 0) + error (_("invalid value for --max-results argument")); + max_results = (int) val; + } + break; } } - mi_symbol_info (MODULES_DOMAIN, regexp, nullptr, true); + mi_symbol_info (MODULES_DOMAIN, regexp, nullptr, true, max_results); } /* Implement -symbol-info-types command. */ @@ -398,15 +422,17 @@ mi_cmd_symbol_info_modules (const char *command, char **argv, int argc) void mi_cmd_symbol_info_types (const char *command, char **argv, int argc) { + int max_results = -1; /* -1 for unlimited. */ const char *regexp = nullptr; enum opt { - NAME_REGEXP_OPT + NAME_REGEXP_OPT, MAX_RESULTS_OPT }; static const struct mi_opt opts[] = { {"-name", NAME_REGEXP_OPT, 1}, + {"-max-results", MAX_RESULTS_OPT, 1}, { 0, 0, 0 } }; @@ -424,10 +450,19 @@ mi_cmd_symbol_info_types (const char *command, char **argv, int argc) case NAME_REGEXP_OPT: regexp = oarg; break; + case MAX_RESULTS_OPT: + { + char *eptr = oarg; + long val = strtol (oarg, &eptr, 10); + if (oarg == eptr || val > INT_MAX || val < 0) + error (_("invalid value for --max-results argument")); + max_results = (int) val; + } + break; } } - mi_symbol_info (TYPES_DOMAIN, regexp, nullptr, true); + mi_symbol_info (TYPES_DOMAIN, regexp, nullptr, true, max_results); } /* Implement -symbol-info-variables command. */ diff --git a/gdb/symtab.c b/gdb/symtab.c index f7affd418cd..0d8c81af83b 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -4351,8 +4351,8 @@ file_matches (const char *file, const std::vector &filenames, return 0; } -/* Helper function for sort_search_symbols_remove_dups and qsort. Can only - sort symbols, not minimal symbols. */ +/* Helper function for std::sort on symbol_search objects. Can only sort + symbols, not minimal symbols. */ int symbol_search::compare_search_syms (const symbol_search &sym_a, @@ -4414,15 +4414,260 @@ treg_matches_sym_type_name (const compiled_regex &treg, return treg.exec (printed_sym_type_name.c_str (), 0, NULL, 0) == 0; } +/* Return true if MSYMBOL is of type KIND. */ -/* Sort the symbols in RESULT and remove duplicates. */ +static bool +search_symbols_is_suitable_msymbol (const enum search_domain kind, + const minimal_symbol *msymbol) +{ + static const enum minimal_symbol_type types[] + = {mst_data, mst_text}; + static const enum minimal_symbol_type types2[] + = {mst_bss, mst_file_text}; + static const enum minimal_symbol_type types3[] + = {mst_file_data, mst_solib_trampoline}; + static const enum minimal_symbol_type types4[] + = {mst_file_bss, mst_text_gnu_ifunc}; -static void -sort_search_symbols_remove_dups (std::vector *result) + gdb_assert (kind == VARIABLES_DOMAIN || kind == FUNCTIONS_DOMAIN); + gdb_assert (kind <= sizeof (types)); + + enum minimal_symbol_type ourtype = types[kind]; + enum minimal_symbol_type ourtype2 = types2[kind]; + enum minimal_symbol_type ourtype3 = types3[kind]; + enum minimal_symbol_type ourtype4 = types4[kind]; + + return (MSYMBOL_TYPE (msymbol) == ourtype + || MSYMBOL_TYPE (msymbol) == ourtype2 + || MSYMBOL_TYPE (msymbol) == ourtype3 + || MSYMBOL_TYPE (msymbol) == ourtype4); +} + +/* Expand symtabs in OBJFILE that match SEARCH_SPEC and PREG. Return true + if any msymbols were seen that we should later consider adding to the + results list. */ + +static bool +search_symbols_expand_symtabs (objfile *objfile, + const search_symbols_spec &search_spec, + const gdb::optional &preg) { - std::sort (result->begin (), result->end ()); - result->erase (std::unique (result->begin (), result->end ()), - result->end ()); + enum search_domain kind = search_spec.kind; + bool found_misc = false; + + if (objfile->sf) + objfile->sf->qf->expand_symtabs_matching + (objfile, + [&] (const char *filename, bool basenames) + { + /* EXPAND_SYMTABS_MATCHING expects a callback + that returns an integer, not a boolean as + FILE_MATCHES does. */ + return file_matches (filename, search_spec.filenames, + basenames) ? 1 : 0; + }, + lookup_name_info::match_any (), + [&] (const char *symname) + { + return (!preg.has_value () + || preg->exec (symname, 0, NULL, 0) == 0); + }, + NULL, + kind); + + /* Here, we search through the minimal symbol tables for functions and + variables that match, and force their symbols to be read. This is in + particular necessary for demangled variable names, which are no longer + put into the partial symbol tables. The symbol will then be found + during the scan of symtabs later. + + For functions, find_pc_symtab should succeed if we have debug info for + the function, for variables we have to call + lookup_symbol_in_objfile_from_linkage_name to determine if the + variable has debug info. If the lookup fails, set found_misc so that + we will rescan to print any matching symbols without debug info. We + only search the objfile the msymbol came from, we no longer search all + objfiles. In large programs (1000s of shared libs) searching all + objfiles is not worth the pain. */ + if (search_spec.filenames.size () == 0 + && (kind == VARIABLES_DOMAIN || kind == FUNCTIONS_DOMAIN)) + { + for (minimal_symbol *msymbol : objfile->msymbols ()) + { + QUIT; + + if (msymbol->created_by_gdb) + continue; + + if (search_symbols_is_suitable_msymbol (kind, msymbol)) + { + if (!preg.has_value () + || preg->exec (MSYMBOL_NATURAL_NAME (msymbol), 0, + NULL, 0) == 0) + { + /* Note: An important side-effect of these + lookup functions is to expand the symbol + table if msymbol is found, for the benefit of + the next loop on compunits. */ + if (kind == FUNCTIONS_DOMAIN + ? (find_pc_compunit_symtab + (MSYMBOL_VALUE_ADDRESS (objfile, msymbol)) + == NULL) + : (lookup_symbol_in_objfile_from_linkage_name + (objfile, MSYMBOL_LINKAGE_NAME (msymbol), + VAR_DOMAIN) + .symbol == NULL)) + found_misc = true; + } + } + } + } + + return found_misc; +} + +/* Add symbols from symtabs in OBJFILE that match SEARCH_SPEC, PREG, and + TREG to the results set RESULTS_SET. Return false if we stop adding + results early due to having already found too many results (based on + max search results limit in SEARCH_SPEC), otherwise return true. */ + +static bool +search_symbols_add_matching_symbols (objfile *objfile, + const search_symbols_spec &search_spec, + const gdb::optional &preg, + const gdb::optional &treg, + std::set *result_set) +{ + enum search_domain kind = search_spec.kind; + + /* Add matching symbols (if not already present). */ + for (compunit_symtab *cust : objfile->compunits ()) + { + const struct blockvector *bv = COMPUNIT_BLOCKVECTOR (cust); + + for (int i = GLOBAL_BLOCK; i <= STATIC_BLOCK; i++) + { + struct block_iterator iter; + struct symbol *sym; + const struct block *b = BLOCKVECTOR_BLOCK (bv, i); + + ALL_BLOCK_SYMBOLS (b, iter, sym) + { + struct symtab *real_symtab = symbol_symtab (sym); + + QUIT; + + /* Check first sole REAL_SYMTAB->FILENAME. It does + not need to be a substring of symtab_to_fullname as + it may contain "./" etc. */ + if ((file_matches (real_symtab->filename, + search_spec.filenames, false) + || ((basenames_may_differ + || file_matches (lbasename (real_symtab->filename), + search_spec.filenames, true)) + && file_matches (symtab_to_fullname (real_symtab), + search_spec.filenames, false))) + && ((!preg.has_value () + || preg->exec (SYMBOL_NATURAL_NAME (sym), 0, + NULL, 0) == 0) + && ((kind == VARIABLES_DOMAIN + && SYMBOL_CLASS (sym) != LOC_TYPEDEF + && SYMBOL_CLASS (sym) != LOC_UNRESOLVED + && SYMBOL_CLASS (sym) != LOC_BLOCK + /* LOC_CONST can be used for more than + just enums, e.g., c++ static const + members. We only want to skip enums + here. */ + && !(SYMBOL_CLASS (sym) == LOC_CONST + && (TYPE_CODE (SYMBOL_TYPE (sym)) + == TYPE_CODE_ENUM)) + && (!treg.has_value () + || treg_matches_sym_type_name (*treg, sym))) + || (kind == FUNCTIONS_DOMAIN + && SYMBOL_CLASS (sym) == LOC_BLOCK + && (!treg.has_value () + || treg_matches_sym_type_name (*treg, + sym))) + || (kind == TYPES_DOMAIN + && SYMBOL_CLASS (sym) == LOC_TYPEDEF + && SYMBOL_DOMAIN (sym) != MODULE_DOMAIN) + || (kind == MODULES_DOMAIN + && SYMBOL_DOMAIN (sym) == MODULE_DOMAIN + && SYMBOL_LINE (sym) != 0)))) + { + if (search_spec.max_search_results == -1 + || result_set->size () < search_spec.max_search_results) + { + /* Match, insert if not already in the results. */ + symbol_search ss (i, sym); + if (result_set->find (ss) == result_set->end ()) + result_set->insert (ss); + } + else + return false; + } + } + } + } + + return true; +} + +/* Add msymbols from OBJFILE that match SEARCH_SPEC and PREG, to the + results vector RESULTS. Return false if we stop adding results early + due to having already found too many results (based on max search + results limit in SEARCH_SPEC), otherwise return true. */ + +static bool +search_symbols_add_matching_msymbols (objfile *objfile, + const search_symbols_spec &search_spec, + const gdb::optional &preg, + std::vector *results) +{ + enum search_domain kind = search_spec.kind; + + for (minimal_symbol *msymbol : objfile->msymbols ()) + { + QUIT; + + if (msymbol->created_by_gdb) + continue; + + if (search_symbols_is_suitable_msymbol (kind, msymbol)) + { + if (!preg.has_value () + || preg->exec (MSYMBOL_NATURAL_NAME (msymbol), 0, + NULL, 0) == 0) + { + /* For functions we can do a quick check of whether the + symbol might be found via find_pc_symtab. */ + if (kind != FUNCTIONS_DOMAIN + || (find_pc_compunit_symtab + (MSYMBOL_VALUE_ADDRESS (objfile, msymbol)) + == NULL)) + { + if (lookup_symbol_in_objfile_from_linkage_name + (objfile, MSYMBOL_LINKAGE_NAME (msymbol), + VAR_DOMAIN) + .symbol == NULL) + { + /* Matching msymbol, add it to the results list. */ + if (search_spec.max_search_results == -1 + || (results->size () + < search_spec.max_search_results)) + { + results->emplace_back (GLOBAL_BLOCK, msymbol, + objfile); + } + else + return false; + } + } + } + } + } + + return true; } /* See symtab.h. */ @@ -4434,39 +4679,13 @@ search_symbols (const search_symbols_spec &search_spec) const char *regexp = search_spec.symbol_regexp; enum search_domain kind = search_spec.kind; const char *t_regexp = search_spec.type_regexp; - int nfiles = search_spec.filenames.size (); - bool exclude_minsyms = search_spec.exclude_minsyms; /* The search. */ - const struct blockvector *bv; - const struct block *b; - int i = 0; - struct block_iterator iter; - struct symbol *sym; - int found_misc = 0; - static const enum minimal_symbol_type types[] - = {mst_data, mst_text, mst_unknown}; - static const enum minimal_symbol_type types2[] - = {mst_bss, mst_file_text, mst_unknown}; - static const enum minimal_symbol_type types3[] - = {mst_file_data, mst_solib_trampoline, mst_unknown}; - static const enum minimal_symbol_type types4[] - = {mst_file_bss, mst_text_gnu_ifunc, mst_unknown}; - enum minimal_symbol_type ourtype; - enum minimal_symbol_type ourtype2; - enum minimal_symbol_type ourtype3; - enum minimal_symbol_type ourtype4; - std::vector result; gdb::optional preg; gdb::optional treg; gdb_assert (kind <= MODULES_DOMAIN); - ourtype = types[kind]; - ourtype2 = types2[kind]; - ourtype3 = types3[kind]; - ourtype4 = types4[kind]; - if (regexp != NULL) { /* Make sure spacing is right for C++ operators. @@ -4515,193 +4734,40 @@ search_symbols (const search_symbols_spec &search_spec) treg.emplace (t_regexp, cflags, _("Invalid regexp")); } - /* Search through the partial symtabs *first* for all symbols - matching the regexp. That way we don't have to reproduce all of - the machinery below. */ - expand_symtabs_matching ([&] (const char *filename, bool basenames) - { - /* EXPAND_SYMTABS_MATCHING expects a callback - that returns an integer, not a boolean as - FILE_MATCHES does. */ - return file_matches (filename, - search_spec.filenames, - basenames) ? 1 : 0; - }, - lookup_name_info::match_any (), - [&] (const char *symname) - { - return (!preg.has_value () - || preg->exec (symname, - 0, NULL, 0) == 0); - }, - NULL, - kind); - - /* Here, we search through the minimal symbol tables for functions - and variables that match, and force their symbols to be read. - This is in particular necessary for demangled variable names, - which are no longer put into the partial symbol tables. - The symbol will then be found during the scan of symtabs below. - - For functions, find_pc_symtab should succeed if we have debug info - for the function, for variables we have to call - lookup_symbol_in_objfile_from_linkage_name to determine if the variable - has debug info. - If the lookup fails, set found_misc so that we will rescan to print - any matching symbols without debug info. - We only search the objfile the msymbol came from, we no longer search - all objfiles. In large programs (1000s of shared libs) searching all - objfiles is not worth the pain. */ - - if (nfiles == 0 && (kind == VARIABLES_DOMAIN || kind == FUNCTIONS_DOMAIN)) - { - for (objfile *objfile : current_program_space->objfiles ()) - { - for (minimal_symbol *msymbol : objfile->msymbols ()) - { - QUIT; - - if (msymbol->created_by_gdb) - continue; - - if (MSYMBOL_TYPE (msymbol) == ourtype - || MSYMBOL_TYPE (msymbol) == ourtype2 - || MSYMBOL_TYPE (msymbol) == ourtype3 - || MSYMBOL_TYPE (msymbol) == ourtype4) - { - if (!preg.has_value () - || preg->exec (MSYMBOL_NATURAL_NAME (msymbol), 0, - NULL, 0) == 0) - { - /* Note: An important side-effect of these - lookup functions is to expand the symbol - table if msymbol is found, for the benefit of - the next loop on compunits. */ - if (kind == FUNCTIONS_DOMAIN - ? (find_pc_compunit_symtab - (MSYMBOL_VALUE_ADDRESS (objfile, msymbol)) - == NULL) - : (lookup_symbol_in_objfile_from_linkage_name - (objfile, MSYMBOL_LINKAGE_NAME (msymbol), - VAR_DOMAIN) - .symbol == NULL)) - found_misc = 1; - } - } - } - } - } - + bool found_misc = false; + std::set result_set; for (objfile *objfile : current_program_space->objfiles ()) { - for (compunit_symtab *cust : objfile->compunits ()) - { - bv = COMPUNIT_BLOCKVECTOR (cust); - for (i = GLOBAL_BLOCK; i <= STATIC_BLOCK; i++) - { - b = BLOCKVECTOR_BLOCK (bv, i); - ALL_BLOCK_SYMBOLS (b, iter, sym) - { - struct symtab *real_symtab = symbol_symtab (sym); - - QUIT; - - /* Check first sole REAL_SYMTAB->FILENAME. It does - not need to be a substring of symtab_to_fullname as - it may contain "./" etc. */ - if ((file_matches (real_symtab->filename, - search_spec.filenames, false) - || ((basenames_may_differ - || file_matches (lbasename (real_symtab->filename), - search_spec.filenames, true)) - && file_matches (symtab_to_fullname (real_symtab), - search_spec.filenames, false))) - && ((!preg.has_value () - || preg->exec (SYMBOL_NATURAL_NAME (sym), 0, - NULL, 0) == 0) - && ((kind == VARIABLES_DOMAIN - && SYMBOL_CLASS (sym) != LOC_TYPEDEF - && SYMBOL_CLASS (sym) != LOC_UNRESOLVED - && SYMBOL_CLASS (sym) != LOC_BLOCK - /* LOC_CONST can be used for more than - just enums, e.g., c++ static const - members. We only want to skip enums - here. */ - && !(SYMBOL_CLASS (sym) == LOC_CONST - && (TYPE_CODE (SYMBOL_TYPE (sym)) - == TYPE_CODE_ENUM)) - && (!treg.has_value () - || treg_matches_sym_type_name (*treg, sym))) - || (kind == FUNCTIONS_DOMAIN - && SYMBOL_CLASS (sym) == LOC_BLOCK - && (!treg.has_value () - || treg_matches_sym_type_name (*treg, - sym))) - || (kind == TYPES_DOMAIN - && SYMBOL_CLASS (sym) == LOC_TYPEDEF - && SYMBOL_DOMAIN (sym) != MODULE_DOMAIN) - || (kind == MODULES_DOMAIN - && SYMBOL_DOMAIN (sym) == MODULE_DOMAIN - && SYMBOL_LINE (sym) != 0)))) - { - /* match */ - result.emplace_back (i, sym); - } - } - } - } - } + /* Expand symtabs within objfile that possibly contain matching + symbols. */ + found_misc + |= search_symbols_expand_symtabs (objfile, search_spec, preg); - if (!result.empty ()) - sort_search_symbols_remove_dups (&result); + /* Find matching symbols within OBJFILE and add them in to + RESULT_SET. */ + if (!search_symbols_add_matching_symbols (objfile, search_spec, preg, + treg, &result_set)) + break; + } - /* If there are no eyes, avoid all contact. I mean, if there are - no debug symbols, then add matching minsyms. But if the user wants - to see symbols matching a type regexp, then never give a minimal symbol, - as we assume that a minimal symbol does not have a type. */ + /* Convert the result set into a sorted result list. */ + std::vector result (result_set.begin (), result_set.end ()); + std::sort (result.begin (), result.end ()); - if ((found_misc || (nfiles == 0 && kind != FUNCTIONS_DOMAIN)) - && !exclude_minsyms + /* If there are no debug symbols, then add matching minsyms. But if the + user wants to see symbols matching a type regexp, then never give a + minimal symbol, as we assume that a minimal symbol does not have a + type. */ + if ((found_misc || (search_spec.filenames.size () == 0 + && kind == VARIABLES_DOMAIN)) + && !search_spec.exclude_minsyms && !treg.has_value ()) { + gdb_assert (kind == VARIABLES_DOMAIN || kind == FUNCTIONS_DOMAIN); for (objfile *objfile : current_program_space->objfiles ()) - { - for (minimal_symbol *msymbol : objfile->msymbols ()) - { - QUIT; - - if (msymbol->created_by_gdb) - continue; - - if (MSYMBOL_TYPE (msymbol) == ourtype - || MSYMBOL_TYPE (msymbol) == ourtype2 - || MSYMBOL_TYPE (msymbol) == ourtype3 - || MSYMBOL_TYPE (msymbol) == ourtype4) - { - if (!preg.has_value () - || preg->exec (MSYMBOL_NATURAL_NAME (msymbol), 0, - NULL, 0) == 0) - { - /* For functions we can do a quick check of whether the - symbol might be found via find_pc_symtab. */ - if (kind != FUNCTIONS_DOMAIN - || (find_pc_compunit_symtab - (MSYMBOL_VALUE_ADDRESS (objfile, msymbol)) - == NULL)) - { - if (lookup_symbol_in_objfile_from_linkage_name - (objfile, MSYMBOL_LINKAGE_NAME (msymbol), - VAR_DOMAIN) - .symbol == NULL) - { - /* match */ - result.emplace_back (i, msymbol, objfile); - } - } - } - } - } - } + if (!search_symbols_add_matching_msymbols (objfile, search_spec, + preg, &result)) + break; } return result; diff --git a/gdb/symtab.h b/gdb/symtab.h index 8852b50a170..b4c58a0074c 100644 --- a/gdb/symtab.h +++ b/gdb/symtab.h @@ -2090,6 +2090,10 @@ struct search_symbols_spec /* The set of source files to search in for matching symbols. */ std::vector filenames; + /* Maximum number of search results, set to -1 for unlimited, otherwise + set to a positive value to limit the number of results returned. */ + int max_search_results = -1; + /* Constructor. */ search_symbols_spec (enum search_domain kind, const char *symbol_regexp = nullptr, diff --git a/gdb/testsuite/gdb.mi/mi-sym-info.exp b/gdb/testsuite/gdb.mi/mi-sym-info.exp index 33fe8657811..80468a47502 100644 --- a/gdb/testsuite/gdb.mi/mi-sym-info.exp +++ b/gdb/testsuite/gdb.mi/mi-sym-info.exp @@ -127,3 +127,28 @@ set lineno2 [gdb_get_line_number "typedef int another_int_t;" ${srcfile2}] mi_gdb_test "120-symbol-info-types --name _int_" \ "120\\^done,symbols=\{debug=\\\[\{filename=\"\[^\"\]+$srcfile\",fullname=\"\[^\"\]+$srcfile\",symbols=\\\[\{line=\"27\",name=\"my_int_t\"\}\\\]\},\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"23\",name=\"another_int_t\"\}\\\]\}\\\]\}" \ "List all types matching _int_" + +# Test the --max-results parameter. +mi_gdb_test "121-symbol-info-functions --max-results 0" \ + "121\\^done,symbols=\{\}" \ + "-symbol-info-functions --max-results 0" + +mi_gdb_test "122-symbol-info-functions --max-results 1" \ + "122\\^done,symbols=\{debug=\\\[\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"39\",name=\"f3\",type=\"int \\(another_int_t\\)\",description=\"int f3\\(another_int_t\\);\"\}\\\]\}\\\]\}" \ + "-symbol-info-functions --max-results 1" + +mi_gdb_test "123-symbol-info-functions --max-results 2" \ + "123\\^done,symbols=\{debug=\\\[\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"33\",name=\"f2\",type=\"float \\(another_float_t\\)\",description=\"float f2\\(another_float_t\\);\"\},\{line=\"39\",name=\"f3\",type=\"int \\(another_int_t\\)\",description=\"int f3\\(another_int_t\\);\"\}\\\]\}\\\]\}" \ + "-symbol-info-functions --max-results 2" + +mi_gdb_test "124-symbol-info-variables --max-results 3" \ + "124\\^done,symbols=\{debug=\\\[\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"21\",name=\"global_f2\",type=\"int\",description=\"int global_f2;\"\},\{line=\"20\",name=\"global_i2\",type=\"int\",description=\"int global_i2;\"\},\{line=\"19\",name=\"global_f1\",type=\"float\",description=\"static float global_f1;\"\}\\\]\}\\\]\}" \ + "-symbol-info-variables --max-results 3" + +mi_gdb_test "125-symbol-info-types --max-results 4" \ + "125\\^done,symbols=\{debug=\\\[\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"24\",name=\"another_float_t\"\},\{line=\"23\",name=\"another_int_t\"\},\{name=\"float\"\},\{name=\"int\"\}\\\]\}\\\]\}" \ + "-symbol-info-types --max-results 4" + + + +