gdb: Introduce global_symbol_searcher

Introduce a new class to wrap up the parameters needed for the
function search_symbols, which has now become a member function of
this new class.

The motivation is that search_symbols already takes a lot of
parameters, and a future commit is going to add even more.  This
commit hopefully makes collecting the state required for a search
easier.

As part of this conversion the list of filenames in which to search
has been converted to a std::vector.

There should be no user visible changes after this commit.

gdb/ChangeLog:

	* python/python.c (gdbpy_rbreak): Convert to using
	global_symbol_searcher.
	* symtab.c (file_matches): Convert return type to bool, change
	file list to std::vector, update header comment.
	(search_symbols): Rename to...
	(global_symbol_searcher::search): ...this and update now its
	a member function of global_symbol_searcher.  Take account of the
	changes to file_matches.
	(symtab_symbol_info): Convert to using global_symbol_searcher.
	(rbreak_command): Likewise.
	(search_module_symbols): Likewise.
	* symtab.h (enum symbol_search): Update comment.
	(search_symbols): Remove declaration.
	(class global_symbol_searcher): New class.

Change-Id: I488ab292a892d9e9e84775c632c5f198b6ad3710
This commit is contained in:
Andrew Burgess 2019-10-10 10:48:01 +01:00
parent 7f3bf38453
commit 470c0b1c9a
4 changed files with 161 additions and 128 deletions

View File

@ -1,3 +1,20 @@
2019-11-27 Andrew Burgess <andrew.burgess@embecosm.com>
* python/python.c (gdbpy_rbreak): Convert to using
global_symbol_searcher.
* symtab.c (file_matches): Convert return type to bool, change
file list to std::vector, update header comment.
(search_symbols): Rename to...
(global_symbol_searcher::search): ...this and update now its
a member function of global_symbol_searcher. Take account of the
changes to file_matches.
(symtab_symbol_info): Convert to using global_symbol_searcher.
(rbreak_command): Likewise.
(search_module_symbols): Likewise.
* symtab.h (enum symbol_search): Update comment.
(search_symbols): Remove declaration.
(class global_symbol_searcher): New class.
2019-11-26 Tom Tromey <tromey@adacore.com>
* cp-support.c (_initialize_cp_support): Conditionally initialize

View File

@ -644,19 +644,6 @@ execute_gdb_command (PyObject *self, PyObject *args, PyObject *kw)
static PyObject *
gdbpy_rbreak (PyObject *self, PyObject *args, PyObject *kw)
{
/* A simple type to ensure clean up of a vector of allocated strings
when a C interface demands a const char *array[] type
interface. */
struct symtab_list_type
{
~symtab_list_type ()
{
for (const char *elem: vec)
xfree ((void *) elem);
}
std::vector<const char *> vec;
};
char *regex = NULL;
std::vector<symbol_search> symbols;
unsigned long count = 0;
@ -666,7 +653,6 @@ gdbpy_rbreak (PyObject *self, PyObject *args, PyObject *kw)
unsigned int throttle = 0;
static const char *keywords[] = {"regex","minsyms", "throttle",
"symtabs", NULL};
symtab_list_type symtab_paths;
if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "s|O!IO", keywords,
&regex, &PyBool_Type,
@ -683,6 +669,12 @@ gdbpy_rbreak (PyObject *self, PyObject *args, PyObject *kw)
minsyms_p = cmp;
}
global_symbol_searcher spec (FUNCTIONS_DOMAIN, regex);
SCOPE_EXIT {
for (const char *elem : spec.filenames)
xfree ((void *) elem);
};
/* The "symtabs" keyword is any Python iterable object that returns
a gdb.Symtab on each iteration. If specified, iterate through
the provided gdb.Symtabs and extract their full path. As
@ -728,20 +720,13 @@ gdbpy_rbreak (PyObject *self, PyObject *args, PyObject *kw)
/* Make sure there is a definite place to store the value of
filename before it is released. */
symtab_paths.vec.push_back (nullptr);
symtab_paths.vec.back () = filename.release ();
spec.filenames.push_back (nullptr);
spec.filenames.back () = filename.release ();
}
}
if (symtab_list)
{
const char **files = symtab_paths.vec.data ();
symbols = search_symbols (regex, FUNCTIONS_DOMAIN, NULL,
symtab_paths.vec.size (), files, false);
}
else
symbols = search_symbols (regex, FUNCTIONS_DOMAIN, NULL, 0, NULL, false);
/* The search spec. */
symbols = spec.search ();
/* Count the number of symbols (both symbols and optionally minimal
symbols) so we can correctly check the throttle limit. */

View File

@ -4347,27 +4347,24 @@ info_sources_command (const char *args, int from_tty)
printf_filtered ("\n");
}
/* Compare FILE against all the NFILES entries of FILES. If BASENAMES is
non-zero compare only lbasename of FILES. */
/* Compare FILE against all the entries of FILENAMES. If BASENAMES is
true compare only lbasename of FILENAMES. */
static int
file_matches (const char *file, const char *files[], int nfiles, int basenames)
static bool
file_matches (const char *file, const std::vector<const char *> &filenames,
bool basenames)
{
int i;
if (filenames.empty ())
return true;
if (file != NULL && nfiles != 0)
for (const char *name : filenames)
{
for (i = 0; i < nfiles; i++)
{
if (compare_filenames_for_search (file, (basenames
? lbasename (files[i])
: files[i])))
return 1;
}
name = (basenames ? lbasename (name) : name);
if (compare_filenames_for_search (file, name))
return true;
}
else if (nfiles == 0)
return 1;
return 0;
return false;
}
/* Helper function for sort_search_symbols_remove_dups and qsort. Can only
@ -4443,30 +4440,10 @@ sort_search_symbols_remove_dups (std::vector<symbol_search> *result)
result->end ());
}
/* Search the symbol table for matches to the regular expression REGEXP,
returning the results.
Only symbols of KIND are searched:
VARIABLES_DOMAIN - search all symbols, excluding functions, type names,
and constants (enums).
if T_REGEXP is not NULL, only returns var that have
a type matching regular expression T_REGEXP.
FUNCTIONS_DOMAIN - search all functions
TYPES_DOMAIN - search all type names
ALL_DOMAIN - an internal error for this function
Within each file the results are sorted locally; each symtab's global and
static blocks are separately alphabetized.
Duplicate entries are removed.
When EXCLUDE_MINSYMS is false then matching minsyms are also returned,
otherwise they are excluded. */
/* See symtab.h. */
std::vector<symbol_search>
search_symbols (const char *regexp, enum search_domain kind,
const char *t_regexp,
int nfiles, const char *files[],
bool exclude_minsyms)
global_symbol_searcher::search () const
{
const struct blockvector *bv;
const struct block *b;
@ -4490,21 +4467,23 @@ search_symbols (const char *regexp, enum search_domain kind,
gdb::optional<compiled_regex> preg;
gdb::optional<compiled_regex> treg;
gdb_assert (kind != ALL_DOMAIN);
gdb_assert (m_kind != ALL_DOMAIN);
ourtype = types[kind];
ourtype2 = types2[kind];
ourtype3 = types3[kind];
ourtype4 = types4[kind];
ourtype = types[m_kind];
ourtype2 = types2[m_kind];
ourtype3 = types3[m_kind];
ourtype4 = types4[m_kind];
if (regexp != NULL)
if (m_symbol_name_regexp != NULL)
{
const char *symbol_name_regexp = m_symbol_name_regexp;
/* Make sure spacing is right for C++ operators.
This is just a courtesy to make the matching less sensitive
to how many spaces the user leaves between 'operator'
and <TYPENAME> or <OPERATOR>. */
const char *opend;
const char *opname = operator_chars (regexp, &opend);
const char *opname = operator_chars (symbol_name_regexp, &opend);
if (*opname)
{
@ -4529,28 +4508,30 @@ search_symbols (const char *regexp, enum search_domain kind,
char *tmp = (char *) alloca (8 + fix + strlen (opname) + 1);
sprintf (tmp, "operator%.*s%s", fix, " ", opname);
regexp = tmp;
symbol_name_regexp = tmp;
}
}
int cflags = REG_NOSUB | (case_sensitivity == case_sensitive_off
? REG_ICASE : 0);
preg.emplace (regexp, cflags, _("Invalid regexp"));
preg.emplace (symbol_name_regexp, cflags,
_("Invalid regexp"));
}
if (t_regexp != NULL)
if (m_symbol_type_regexp != NULL)
{
int cflags = REG_NOSUB | (case_sensitivity == case_sensitive_off
? REG_ICASE : 0);
treg.emplace (t_regexp, cflags, _("Invalid regexp"));
treg.emplace (m_symbol_type_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. */
/* 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, files, nfiles,
return file_matches (filename, filenames,
basenames);
},
lookup_name_info::match_any (),
@ -4561,7 +4542,7 @@ search_symbols (const char *regexp, enum search_domain kind,
0, NULL, 0) == 0);
},
NULL,
kind);
m_kind);
/* Here, we search through the minimal symbol tables for functions
and variables that match, and force their symbols to be read.
@ -4579,7 +4560,8 @@ search_symbols (const char *regexp, enum search_domain kind,
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))
if (filenames.empty () && (m_kind == VARIABLES_DOMAIN
|| m_kind == FUNCTIONS_DOMAIN))
{
for (objfile *objfile : current_program_space->objfiles ())
{
@ -4603,7 +4585,7 @@ search_symbols (const char *regexp, enum search_domain kind,
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
if (m_kind == FUNCTIONS_DOMAIN
? (find_pc_compunit_symtab
(MSYMBOL_VALUE_ADDRESS (objfile, msymbol))
== NULL)
@ -4634,16 +4616,16 @@ search_symbols (const char *regexp, enum search_domain kind,
/* Check first sole REAL_SYMTAB->FILENAME. It does
not need to be a substring of symtab_to_fullname as
it may contain "./" etc. */
if ((file_matches (real_symtab->filename, files, nfiles, 0)
if ((file_matches (real_symtab->filename, filenames, false)
|| ((basenames_may_differ
|| file_matches (lbasename (real_symtab->filename),
files, nfiles, 1))
filenames, true))
&& file_matches (symtab_to_fullname (real_symtab),
files, nfiles, 0)))
filenames, false)))
&& ((!preg.has_value ()
|| preg->exec (sym->natural_name (), 0,
NULL, 0) == 0)
&& ((kind == VARIABLES_DOMAIN
&& ((m_kind == VARIABLES_DOMAIN
&& SYMBOL_CLASS (sym) != LOC_TYPEDEF
&& SYMBOL_CLASS (sym) != LOC_UNRESOLVED
&& SYMBOL_CLASS (sym) != LOC_BLOCK
@ -4656,15 +4638,15 @@ search_symbols (const char *regexp, enum search_domain kind,
== TYPE_CODE_ENUM))
&& (!treg.has_value ()
|| treg_matches_sym_type_name (*treg, sym)))
|| (kind == FUNCTIONS_DOMAIN
|| (m_kind == FUNCTIONS_DOMAIN
&& SYMBOL_CLASS (sym) == LOC_BLOCK
&& (!treg.has_value ()
|| treg_matches_sym_type_name (*treg,
sym)))
|| (kind == TYPES_DOMAIN
|| (m_kind == TYPES_DOMAIN
&& SYMBOL_CLASS (sym) == LOC_TYPEDEF
&& SYMBOL_DOMAIN (sym) != MODULE_DOMAIN)
|| (kind == MODULES_DOMAIN
|| (m_kind == MODULES_DOMAIN
&& SYMBOL_DOMAIN (sym) == MODULE_DOMAIN
&& SYMBOL_LINE (sym) != 0))))
{
@ -4679,13 +4661,13 @@ search_symbols (const char *regexp, enum search_domain kind,
if (!result.empty ())
sort_search_symbols_remove_dups (&result);
/* 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 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 || (nfiles == 0 && kind != FUNCTIONS_DOMAIN))
&& !exclude_minsyms
if ((found_misc || (filenames.empty () && m_kind != FUNCTIONS_DOMAIN))
&& !m_exclude_minsyms
&& !treg.has_value ())
{
for (objfile *objfile : current_program_space->objfiles ())
@ -4708,7 +4690,7 @@ search_symbols (const char *regexp, enum search_domain kind,
{
/* For functions we can do a quick check of whether the
symbol might be found via find_pc_symtab. */
if (kind != FUNCTIONS_DOMAIN
if (m_kind != FUNCTIONS_DOMAIN
|| (find_pc_compunit_symtab
(MSYMBOL_VALUE_ADDRESS (objfile, msymbol))
== NULL))
@ -4847,10 +4829,10 @@ symtab_symbol_info (bool quiet, bool exclude_minsyms,
if (regexp != nullptr && *regexp == '\0')
regexp = nullptr;
/* Must make sure that if we're interrupted, symbols gets freed. */
std::vector<symbol_search> symbols = search_symbols (regexp, kind,
t_regexp, 0, NULL,
exclude_minsyms);
global_symbol_searcher spec (kind, regexp);
spec.set_symbol_type_regexp (t_regexp);
spec.set_exclude_minsyms (exclude_minsyms);
std::vector<symbol_search> symbols = spec.search ();
if (!quiet)
{
@ -5081,11 +5063,9 @@ static void
rbreak_command (const char *regexp, int from_tty)
{
std::string string;
const char **files = NULL;
const char *file_name;
int nfiles = 0;
const char *file_name = nullptr;
if (regexp)
if (regexp != nullptr)
{
const char *colon = strchr (regexp, ':');
@ -5101,17 +5081,14 @@ rbreak_command (const char *regexp, int from_tty)
while (isspace (local_name[colon_index]))
local_name[colon_index--] = 0;
file_name = local_name;
files = &file_name;
nfiles = 1;
regexp = skip_spaces (colon + 1);
}
}
std::vector<symbol_search> symbols = search_symbols (regexp,
FUNCTIONS_DOMAIN,
NULL,
nfiles, files,
false);
global_symbol_searcher spec (FUNCTIONS_DOMAIN, regexp);
if (file_name != nullptr)
spec.filenames.push_back (file_name);
std::vector<symbol_search> symbols = spec.search ();
scoped_rbreak_breakpoints finalize;
for (const symbol_search &p : symbols)
@ -6345,17 +6322,17 @@ search_module_symbols (const char *module_regexp, const char *regexp,
std::vector<module_symbol_search> results;
/* Search for all modules matching MODULE_REGEXP. */
std::vector<symbol_search> modules = search_symbols (module_regexp,
MODULES_DOMAIN,
NULL, 0, NULL,
true);
global_symbol_searcher spec1 (MODULES_DOMAIN, module_regexp);
spec1.set_exclude_minsyms (true);
std::vector<symbol_search> modules = spec1.search ();
/* Now search for all symbols of the required KIND matching the required
regular expressions. We figure out which ones are in which modules
below. */
std::vector<symbol_search> symbols = search_symbols (regexp, kind,
type_regexp, 0,
NULL, true);
global_symbol_searcher spec2 (kind, regexp);
spec2.set_symbol_type_regexp (type_regexp);
spec2.set_exclude_minsyms (true);
std::vector<symbol_search> symbols = spec2.search ();
/* Now iterate over all MODULES, checking to see which items from
SYMBOLS are in each module. */

View File

@ -797,7 +797,7 @@ gdb_static_assert (NR_DOMAINS <= (1 << SYMBOL_DOMAIN_BITS));
extern const char *domain_name (domain_enum);
/* Searching domains, used for `search_symbols'. Element numbers are
/* Searching domains, used when searching for symbols. Element numbers are
hardcoded in GDB, check all enum uses before changing it. */
enum search_domain
@ -2011,11 +2011,9 @@ extern struct symbol *fixup_symbol_section (struct symbol *,
extern symbol *find_function_alias_target (bound_minimal_symbol msymbol);
/* Symbol searching */
/* Note: struct symbol_search, search_symbols, et.al. are declared here,
instead of making them local to symtab.c, for gdbtk's sake. */
/* When using search_symbols, a vector of the following structs is
returned. */
/* When using the symbol_searcher struct to search for symbols, a vector of
the following structs is returned. */
struct symbol_search
{
symbol_search (int block_, struct symbol *symbol_)
@ -2064,12 +2062,68 @@ private:
const symbol_search &sym_b);
};
extern std::vector<symbol_search> search_symbols (const char *,
enum search_domain,
const char *,
int,
const char **,
bool);
/* In order to search for global symbols of a particular kind matching
particular regular expressions, create an instance of this structure and
call the SEARCH member function. */
class global_symbol_searcher
{
public:
/* Constructor. */
global_symbol_searcher (enum search_domain kind,
const char *symbol_name_regexp)
: m_kind (kind),
m_symbol_name_regexp (symbol_name_regexp)
{
/* The symbol searching is designed to only find one kind of thing. */
gdb_assert (m_kind != ALL_DOMAIN);
}
/* Set the optional regexp that matches against the symbol type. */
void set_symbol_type_regexp (const char *regexp)
{
m_symbol_type_regexp = regexp;
}
/* Set the flag to exclude minsyms from the search results. */
void set_exclude_minsyms (bool exclude_minsyms)
{
m_exclude_minsyms = exclude_minsyms;
}
/* Search the symbols from all objfiles in the current program space
looking for matches as defined by the current state of this object.
Within each file the results are sorted locally; each symtab's global
and static blocks are separately alphabetized. Duplicate entries are
removed. */
std::vector<symbol_search> search () const;
/* The set of source files to search in for matching symbols. This is
currently public so that it can be populated after this object has
been constructed. */
std::vector<const char *> filenames;
private:
/* The kind of symbols are we searching for.
VARIABLES_DOMAIN - Search all symbols, excluding functions, type
names, and constants (enums).
FUNCTIONS_DOMAIN - Search all functions..
TYPES_DOMAIN - Search all type names.
MODULES_DOMAIN - Search all Fortran modules.
ALL_DOMAIN - Not valid for this function. */
enum search_domain m_kind;
/* Regular expression to match against the symbol name. */
const char *m_symbol_name_regexp = nullptr;
/* 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;
};
/* When searching for Fortran symbols within modules (functions/variables)
we return a vector of this type. The first item in the pair is the