/* Symbol table lookup for the GNU debugger, GDB.
- Copyright (C) 1986-2019 Free Software Foundation, Inc.
+ Copyright (C) 1986-2020 Free Software Foundation, Inc.
This file is part of GDB.
} value;
};
+/* Clear out SLOT. */
+
+static void
+symbol_cache_clear_slot (struct symbol_cache_slot *slot)
+{
+ if (slot->state == SYMBOL_SLOT_NOT_FOUND)
+ xfree (slot->value.not_found.name);
+ slot->state = SYMBOL_SLOT_UNUSED;
+}
+
/* Symbols don't specify global vs static block.
So keep them in separate caches. */
struct symbol_cache_slot symbols[1];
};
+/* Clear all slots of BSC and free BSC. */
+
+static void
+destroy_block_symbol_cache (struct block_symbol_cache *bsc)
+{
+ if (bsc != nullptr)
+ {
+ for (unsigned int i = 0; i < bsc->size; i++)
+ symbol_cache_clear_slot (&bsc->symbols[i]);
+ xfree (bsc);
+ }
+}
+
/* The symbol cache.
Searching for symbols in the static and global blocks over multiple objfiles
~symbol_cache ()
{
- xfree (global_symbols);
- xfree (static_symbols);
+ destroy_block_symbol_cache (global_symbols);
+ destroy_block_symbol_cache (static_symbols);
}
struct block_symbol_cache *global_symbols = nullptr;
const char *name,
struct obstack *obstack)
{
- if (gsymbol->language == language_ada)
+ if (gsymbol->language () == language_ada)
{
if (name == NULL)
{
const char *
symbol_get_demangled_name (const struct general_symbol_info *gsymbol)
{
- if (gsymbol->language == language_ada)
+ if (gsymbol->language () == language_ada)
{
if (!gsymbol->ada_mangled)
return NULL;
depending upon the language for the symbol. */
void
-symbol_set_language (struct general_symbol_info *gsymbol,
- enum language language,
- struct obstack *obstack)
+general_symbol_info::set_language (enum language language,
+ struct obstack *obstack)
{
- gsymbol->language = language;
- if (gsymbol->language == language_cplus
- || gsymbol->language == language_d
- || gsymbol->language == language_go
- || gsymbol->language == language_objc
- || gsymbol->language == language_fortran)
+ m_language = language;
+ if (language == language_cplus
+ || language == language_d
+ || language == language_go
+ || language == language_objc
+ || language == language_fortran)
{
- symbol_set_demangled_name (gsymbol, NULL, obstack);
+ symbol_set_demangled_name (this, NULL, obstack);
}
- else if (gsymbol->language == language_ada)
+ else if (language == language_ada)
{
- gdb_assert (gsymbol->ada_mangled == 0);
- gsymbol->language_specific.obstack = obstack;
+ gdb_assert (ada_mangled == 0);
+ language_specific.obstack = obstack;
}
else
{
- memset (&gsymbol->language_specific, 0,
- sizeof (gsymbol->language_specific));
+ memset (&language_specific, 0, sizeof (language_specific));
}
}
char *demangled = NULL;
int i;
- if (gsymbol->language == language_unknown)
- gsymbol->language = language_auto;
+ if (gsymbol->language () == language_unknown)
+ gsymbol->m_language = language_auto;
- if (gsymbol->language != language_auto)
+ if (gsymbol->language () != language_auto)
{
- const struct language_defn *lang = language_def (gsymbol->language);
+ const struct language_defn *lang = language_def (gsymbol->language ());
language_sniff_from_mangled_name (lang, mangled, &demangled);
return demangled;
if (language_sniff_from_mangled_name (lang, mangled, &demangled))
{
- gsymbol->language = l;
+ gsymbol->m_language = l;
return demangled;
}
}
so the pointer can be discarded after calling this function. */
void
-symbol_set_names (struct general_symbol_info *gsymbol,
- gdb::string_view linkage_name, bool copy_name,
- struct objfile_per_bfd_storage *per_bfd)
+general_symbol_info::compute_and_set_names (gdb::string_view linkage_name,
+ bool copy_name,
+ objfile_per_bfd_storage *per_bfd,
+ gdb::optional<hashval_t> hash)
{
struct demangled_name_entry **slot;
- if (gsymbol->language == language_ada)
+ if (language () == language_ada)
{
/* In Ada, we do the symbol lookups using the mangled name, so
we can save some space by not storing the demangled name. */
if (!copy_name)
- gsymbol->name = linkage_name.data ();
+ m_name = linkage_name.data ();
else
- {
- char *name = (char *) obstack_alloc (&per_bfd->storage_obstack,
- linkage_name.length () + 1);
-
- memcpy (name, linkage_name.data (), linkage_name.length ());
- name[linkage_name.length ()] = '\0';
- gsymbol->name = name;
- }
- symbol_set_demangled_name (gsymbol, NULL, &per_bfd->storage_obstack);
+ m_name = obstack_strndup (&per_bfd->storage_obstack,
+ linkage_name.data (),
+ linkage_name.length ());
+ symbol_set_demangled_name (this, NULL, &per_bfd->storage_obstack);
return;
}
create_demangled_names_hash (per_bfd);
struct demangled_name_entry entry (linkage_name);
+ if (!hash.has_value ())
+ hash = hash_demangled_name_entry (&entry);
slot = ((struct demangled_name_entry **)
- htab_find_slot (per_bfd->demangled_names_hash.get (),
- &entry, INSERT));
+ htab_find_slot_with_hash (per_bfd->demangled_names_hash.get (),
+ &entry, *hash, INSERT));
+
+ /* The const_cast is safe because the only reason it is already
+ initialized is if we purposefully set it from a background
+ thread to avoid doing the work here. However, it is still
+ allocated from the heap and needs to be freed by us, just
+ like if we called symbol_find_demangled_name here. If this is
+ nullptr, we call symbol_find_demangled_name below, but we put
+ this smart pointer here to be sure that we don't leak this name. */
+ gdb::unique_xmalloc_ptr<char> demangled_name
+ (const_cast<char *> (language_specific.demangled_name));
/* If this name is not in the hash table, add it. */
if (*slot == NULL
/* A C version of the symbol may have already snuck into the table.
This happens to, e.g., main.init (__go_init_main). Cope. */
- || (gsymbol->language == language_go && (*slot)->demangled == nullptr))
+ || (language () == language_go && (*slot)->demangled == nullptr))
{
/* A 0-terminated copy of the linkage name. Callers must set COPY_NAME
to true if the string might not be nullterminated. We have to make
else
linkage_name_copy = linkage_name;
- /* The const_cast is safe because the only reason it is already
- initialized is if we purposefully set it from a background
- thread to avoid doing the work here. However, it is still
- allocated from the heap and needs to be freed by us, just
- like if we called symbol_find_demangled_name here. */
- gdb::unique_xmalloc_ptr<char> demangled_name
- (gsymbol->language_specific.demangled_name
- ? const_cast<char *> (gsymbol->language_specific.demangled_name)
- : symbol_find_demangled_name (gsymbol, linkage_name_copy.data ()));
+ if (demangled_name.get () == nullptr)
+ demangled_name.reset
+ (symbol_find_demangled_name (this, linkage_name_copy.data ()));
/* Suppose we have demangled_name==NULL, copy_name==0, and
linkage_name_copy==linkage_name. In this case, we already have the
(gdb::string_view (mangled_ptr, linkage_name.length ()));
}
(*slot)->demangled = std::move (demangled_name);
- (*slot)->language = gsymbol->language;
+ (*slot)->language = language ();
}
- else if (gsymbol->language == language_unknown
- || gsymbol->language == language_auto)
- gsymbol->language = (*slot)->language;
+ else if (language () == language_unknown || language () == language_auto)
+ m_language = (*slot)->language;
- gsymbol->name = (*slot)->mangled.data ();
- if ((*slot)->demangled != nullptr)
- symbol_set_demangled_name (gsymbol, (*slot)->demangled.get (),
- &per_bfd->storage_obstack);
- else
- symbol_set_demangled_name (gsymbol, NULL, &per_bfd->storage_obstack);
+ m_name = (*slot)->mangled.data ();
+ symbol_set_demangled_name (this, (*slot)->demangled.get (),
+ &per_bfd->storage_obstack);
}
/* See symtab.h. */
const char *
general_symbol_info::natural_name () const
{
- switch (language)
+ switch (language ())
{
case language_cplus:
case language_d:
default:
break;
}
- return name;
+ return linkage_name ();
}
/* See symtab.h. */
{
const char *dem_name = NULL;
- switch (language)
+ switch (language ())
{
case language_cplus:
case language_d:
const char *
general_symbol_info::search_name () const
{
- if (language == language_ada)
- return name;
+ if (language () == language_ada)
+ return linkage_name ();
else
return natural_name ();
}
const lookup_name_info &name)
{
symbol_name_matcher_ftype *name_match
- = get_symbol_name_matcher (language_def (gsymbol->language), name);
+ = get_symbol_name_matcher (language_def (gsymbol->language ()), name);
return name_match (gsymbol->search_name (), name, NULL);
}
if (!SYMBOL_MATCHES_SEARCH_NAME (sym, lookup_name))
return 0;
- if (!symbol_matches_domain (SYMBOL_LANGUAGE (sym),
- slot_domain, domain))
+ if (!symbol_matches_domain (sym->language (), slot_domain, domain))
return 0;
}
}
&& new_size == 0))
return;
- xfree (cache->global_symbols);
- xfree (cache->static_symbols);
+ destroy_block_symbol_cache (cache->global_symbols);
+ destroy_block_symbol_cache (cache->static_symbols);
if (new_size == 0)
{
return {};
}
-/* Clear out SLOT. */
-
-static void
-symbol_cache_clear_slot (struct symbol_cache_slot *slot)
-{
- if (slot->state == SYMBOL_SLOT_NOT_FOUND)
- xfree (slot->value.not_found.name);
- slot->state = SYMBOL_SLOT_UNUSED;
-}
-
/* Mark SYMBOL as found in SLOT.
OBJFILE_CONTEXT is the current objfile when the lookup was done, or NULL
if it's not needed to distinguish lookups (STATIC_BLOCK). It is *not*
e.g. on PowerPC64, where the minimal symbol for a function will
point to the function descriptor, while the debug symbol will
point to the actual function code. */
- msym = lookup_minimal_symbol_by_pc_name (addr, ginfo->name, objfile);
+ msym = lookup_minimal_symbol_by_pc_name (addr, ginfo->linkage_name (),
+ objfile);
if (msym)
ginfo->section = MSYMBOL_SECTION (msym);
else
So, instead, search the section table when lookup by name has
failed. The ``addr'' and ``endaddr'' fields may have already
- been relocated. If so, the relocation offset (i.e. the
- ANOFFSET value) needs to be subtracted from these values when
- performing the comparison. We unconditionally subtract it,
- because, when no relocation has been performed, the ANOFFSET
- value will simply be zero.
+ been relocated. If so, the relocation offset needs to be
+ subtracted from these values when performing the comparison.
+ We unconditionally subtract it, because, when no relocation
+ has been performed, the value will simply be zero.
The address of the symbol whose section we're fixing up HAS
NOT BEEN adjusted (relocated) yet. It can't have been since
ALL_OBJFILE_OSECTIONS (objfile, s)
{
int idx = s - objfile->sections;
- CORE_ADDR offset = ANOFFSET (objfile->section_offsets, idx);
+ CORE_ADDR offset = objfile->section_offsets[idx];
if (fallback == -1)
fallback = idx;
ALL_BLOCK_SYMBOLS_WITH_NAME (block, name, iter, sym)
{
- if (symbol_matches_domain (SYMBOL_LANGUAGE (sym),
- SYMBOL_DOMAIN (sym), domain))
+ if (symbol_matches_domain (sym->language (), SYMBOL_DOMAIN (sym), domain))
{
struct block_symbol block_sym = {sym, block};
struct linetable_entry *last = item + len;
item = std::upper_bound (first, last, pc, pc_compare);
if (item != first)
- prev = item - 1; /* Found a matching item. */
+ {
+ /* Found a matching item. Skip backwards over any end of
+ sequence markers. */
+ for (prev = item - 1; prev->line == 0 && prev != first; prev--)
+ /* Nothing. */;
+ }
/* At this point, prev points at the line whose start addr is <= pc, and
item points at the next line. If we ran off the end of the linetable
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
- 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,
return treg.exec (printed_sym_type_name.c_str (), 0, NULL, 0) == 0;
}
+/* See symtab.h. */
+
+bool
+global_symbol_searcher::is_suitable_msymbol
+ (const enum search_domain kind, const minimal_symbol *msymbol)
+{
+ switch (MSYMBOL_TYPE (msymbol))
+ {
+ case mst_data:
+ case mst_bss:
+ case mst_file_data:
+ case mst_file_bss:
+ return kind == VARIABLES_DOMAIN;
+ case mst_text:
+ case mst_file_text:
+ case mst_solib_trampoline:
+ case mst_text_gnu_ifunc:
+ return kind == FUNCTIONS_DOMAIN;
+ default:
+ return false;
+ }
+}
-/* Sort the symbols in RESULT and remove duplicates. */
+/* See symtab.h. */
-static void
-sort_search_symbols_remove_dups (std::vector<symbol_search> *result)
+bool
+global_symbol_searcher::expand_symtabs
+ (objfile *objfile, const gdb::optional<compiled_regex> &preg) const
+{
+ enum search_domain kind = m_kind;
+ bool found_msymbol = false;
+
+ if (objfile->sf)
+ objfile->sf->qf->expand_symtabs_matching
+ (objfile,
+ [&] (const char *filename, bool basenames)
+ {
+ return file_matches (filename, filenames, basenames);
+ },
+ lookup_name_info::match_any (),
+ [&] (const char *symname)
+ {
+ return (!preg.has_value ()
+ || preg->exec (symname, 0, NULL, 0) == 0);
+ },
+ NULL,
+ kind);
+
+ /* Here, we search through the minimal symbol tables for functions and
+ variables that match, and force their symbols to be read. This is in
+ particular necessary for demangled variable names, which are no longer
+ put into the partial symbol tables. The symbol will then be found
+ during the scan of symtabs later.
+
+ For functions, find_pc_symtab should succeed if we have debug info for
+ the function, for variables we have to call
+ lookup_symbol_in_objfile_from_linkage_name to determine if the
+ variable has debug info. If the lookup fails, set found_msymbol so
+ that we will rescan to print any matching symbols without debug info.
+ We only search the objfile the msymbol came from, we no longer search
+ all objfiles. In large programs (1000s of shared libs) searching all
+ objfiles is not worth the pain. */
+ if (filenames.empty ()
+ && (kind == VARIABLES_DOMAIN || kind == FUNCTIONS_DOMAIN))
+ {
+ for (minimal_symbol *msymbol : objfile->msymbols ())
+ {
+ QUIT;
+
+ if (msymbol->created_by_gdb)
+ continue;
+
+ if (is_suitable_msymbol (kind, msymbol))
+ {
+ if (!preg.has_value ()
+ || preg->exec (msymbol->natural_name (), 0,
+ NULL, 0) == 0)
+ {
+ /* An important side-effect of these lookup functions is
+ to expand the symbol table if msymbol is found, later
+ in the process we will add matching symbols or
+ msymbols to the results list, and that requires that
+ the symbols tables are expanded. */
+ if (kind == FUNCTIONS_DOMAIN
+ ? (find_pc_compunit_symtab
+ (MSYMBOL_VALUE_ADDRESS (objfile, msymbol))
+ == NULL)
+ : (lookup_symbol_in_objfile_from_linkage_name
+ (objfile, msymbol->linkage_name (),
+ VAR_DOMAIN)
+ .symbol == NULL))
+ found_msymbol = true;
+ }
+ }
+ }
+ }
+
+ return found_msymbol;
+}
+
+/* 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
{
- std::sort (result->begin (), result->end ());
- result->erase (std::unique (result->begin (), result->end ()),
- result->end ());
+ 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 (block_enum block : { GLOBAL_BLOCK, STATIC_BLOCK })
+ {
+ struct block_iterator iter;
+ struct symbol *sym;
+ const struct block *b = BLOCKVECTOR_BLOCK (bv, block);
+
+ ALL_BLOCK_SYMBOLS (b, iter, sym)
+ {
+ struct symtab *real_symtab = symbol_symtab (sym);
+
+ QUIT;
+
+ /* Check first sole REAL_SYMTAB->FILENAME. It does
+ not need to be a substring of symtab_to_fullname as
+ it may contain "./" etc. */
+ if ((file_matches (real_symtab->filename, filenames, false)
+ || ((basenames_may_differ
+ || file_matches (lbasename (real_symtab->filename),
+ filenames, true))
+ && file_matches (symtab_to_fullname (real_symtab),
+ filenames, false)))
+ && ((!preg.has_value ()
+ || preg->exec (sym->natural_name (), 0,
+ NULL, 0) == 0)
+ && ((kind == VARIABLES_DOMAIN
+ && SYMBOL_CLASS (sym) != LOC_TYPEDEF
+ && SYMBOL_CLASS (sym) != LOC_UNRESOLVED
+ && SYMBOL_CLASS (sym) != LOC_BLOCK
+ /* LOC_CONST can be used for more than
+ just enums, e.g., c++ static const
+ members. We only want to skip enums
+ here. */
+ && !(SYMBOL_CLASS (sym) == LOC_CONST
+ && (TYPE_CODE (SYMBOL_TYPE (sym))
+ == TYPE_CODE_ENUM))
+ && (!treg.has_value ()
+ || treg_matches_sym_type_name (*treg, sym)))
+ || (kind == FUNCTIONS_DOMAIN
+ && SYMBOL_CLASS (sym) == LOC_BLOCK
+ && (!treg.has_value ()
+ || treg_matches_sym_type_name (*treg,
+ sym)))
+ || (kind == TYPES_DOMAIN
+ && SYMBOL_CLASS (sym) == LOC_TYPEDEF
+ && SYMBOL_DOMAIN (sym) != MODULE_DOMAIN)
+ || (kind == MODULES_DOMAIN
+ && SYMBOL_DOMAIN (sym) == MODULE_DOMAIN
+ && SYMBOL_LINE (sym) != 0))))
+ {
+ if (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;
}
-/* Search the symbol table for matches to the regular expression REGEXP,
- returning the results.
+/* 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;
- 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
+ for (minimal_symbol *msymbol : objfile->msymbols ())
+ {
+ QUIT;
+
+ if (msymbol->created_by_gdb)
+ continue;
+
+ if (is_suitable_msymbol (kind, msymbol))
+ {
+ if (!preg.has_value ()
+ || preg->exec (msymbol->natural_name (), 0,
+ NULL, 0) == 0)
+ {
+ /* For functions we can do a quick check of whether the
+ symbol might be found via find_pc_symtab. */
+ if (kind != FUNCTIONS_DOMAIN
+ || (find_pc_compunit_symtab
+ (MSYMBOL_VALUE_ADDRESS (objfile, msymbol))
+ == NULL))
+ {
+ if (lookup_symbol_in_objfile_from_linkage_name
+ (objfile, msymbol->linkage_name (),
+ VAR_DOMAIN).symbol == NULL)
+ {
+ /* Matching msymbol, add it to the results list. */
+ if (results->size () < m_max_search_results)
+ results->emplace_back (GLOBAL_BLOCK, msymbol, objfile);
+ else
+ return false;
+ }
+ }
+ }
+ }
+ }
- Within each file the results are sorted locally; each symtab's global and
- static blocks are separately alphabetized.
- Duplicate entries are removed.
+ return true;
+}
- 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;
- int i = 0;
- struct block_iterator iter;
- struct symbol *sym;
- int found_misc = 0;
- static const enum minimal_symbol_type types[]
- = {mst_data, mst_text, mst_unknown};
- static const enum minimal_symbol_type types2[]
- = {mst_bss, mst_file_text, mst_unknown};
- static const enum minimal_symbol_type types3[]
- = {mst_file_data, mst_solib_trampoline, mst_unknown};
- static const enum minimal_symbol_type types4[]
- = {mst_file_bss, mst_text_gnu_ifunc, mst_unknown};
- enum minimal_symbol_type ourtype;
- enum minimal_symbol_type ourtype2;
- enum minimal_symbol_type ourtype3;
- enum minimal_symbol_type ourtype4;
- std::vector<symbol_search> result;
gdb::optional<compiled_regex> preg;
gdb::optional<compiled_regex> treg;
- gdb_assert (kind != ALL_DOMAIN);
+ gdb_assert (m_kind != ALL_DOMAIN);
- ourtype = types[kind];
- ourtype2 = types2[kind];
- ourtype3 = types3[kind];
- ourtype4 = types4[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)
{
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"));
- }
-
- /* 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)
- {
- return file_matches (filename, files, nfiles,
- basenames);
- },
- lookup_name_info::match_any (),
- [&] (const char *symname)
- {
- return (!preg.has_value ()
- || preg->exec (symname,
- 0, NULL, 0) == 0);
- },
- NULL,
- kind);
-
- /* Here, we search through the minimal symbol tables for functions
- and variables that match, and force their symbols to be read.
- This is in particular necessary for demangled variable names,
- which are no longer put into the partial symbol tables.
- The symbol will then be found during the scan of symtabs 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 (), 0,
- NULL, 0) == 0)
- {
- /* Note: An important side-effect of these
- lookup functions is to expand the symbol
- table if msymbol is found, for the benefit of
- the next loop on compunits. */
- if (kind == FUNCTIONS_DOMAIN
- ? (find_pc_compunit_symtab
- (MSYMBOL_VALUE_ADDRESS (objfile, msymbol))
- == NULL)
- : (lookup_symbol_in_objfile_from_linkage_name
- (objfile, msymbol->linkage_name (), VAR_DOMAIN)
- .symbol == NULL))
- found_misc = 1;
- }
- }
- }
- }
+ treg.emplace (m_symbol_type_regexp, cflags,
+ _("Invalid regexp"));
}
+ bool found_msymbol = 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);
-
- 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, files, nfiles, 0)
- || ((basenames_may_differ
- || file_matches (lbasename (real_symtab->filename),
- files, nfiles, 1))
- && file_matches (symtab_to_fullname (real_symtab),
- files, nfiles, 0)))
- && ((!preg.has_value ()
- || preg->exec (sym->natural_name (), 0,
- NULL, 0) == 0)
- && ((kind == VARIABLES_DOMAIN
- && SYMBOL_CLASS (sym) != LOC_TYPEDEF
- && SYMBOL_CLASS (sym) != LOC_UNRESOLVED
- && SYMBOL_CLASS (sym) != LOC_BLOCK
- /* LOC_CONST can be used for more than
- just enums, e.g., c++ static const
- members. We only want to skip enums
- here. */
- && !(SYMBOL_CLASS (sym) == LOC_CONST
- && (TYPE_CODE (SYMBOL_TYPE (sym))
- == TYPE_CODE_ENUM))
- && (!treg.has_value ()
- || treg_matches_sym_type_name (*treg, sym)))
- || (kind == FUNCTIONS_DOMAIN
- && SYMBOL_CLASS (sym) == LOC_BLOCK
- && (!treg.has_value ()
- || treg_matches_sym_type_name (*treg,
- sym)))
- || (kind == TYPES_DOMAIN
- && SYMBOL_CLASS (sym) == LOC_TYPEDEF
- && SYMBOL_DOMAIN (sym) != MODULE_DOMAIN)
- || (kind == MODULES_DOMAIN
- && SYMBOL_DOMAIN (sym) == MODULE_DOMAIN
- && SYMBOL_LINE (sym) != 0))))
- {
- /* match */
- result.emplace_back (i, sym);
- }
- }
- }
- }
- }
+ /* Expand symtabs within objfile that possibly contain matching
+ symbols. */
+ found_msymbol |= expand_symtabs (objfile, preg);
- if (!result.empty ())
- sort_search_symbols_remove_dups (&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 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, as std::set is
+ defined to be sorted then no explicit call to std::sort is needed. */
+ std::vector<symbol_search> result (result_set.begin (), result_set.end ());
- if ((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_msymbol || (filenames.empty () && m_kind == VARIABLES_DOMAIN))
+ && !m_exclude_minsyms
&& !treg.has_value ())
{
+ gdb_assert (m_kind == VARIABLES_DOMAIN || m_kind == FUNCTIONS_DOMAIN);
for (objfile *objfile : current_program_space->objfiles ())
- {
- for (minimal_symbol *msymbol : objfile->msymbols ())
- {
- QUIT;
-
- if (msymbol->created_by_gdb)
- continue;
-
- if (MSYMBOL_TYPE (msymbol) == ourtype
- || MSYMBOL_TYPE (msymbol) == ourtype2
- || MSYMBOL_TYPE (msymbol) == ourtype3
- || MSYMBOL_TYPE (msymbol) == ourtype4)
- {
- if (!preg.has_value ()
- || preg->exec (msymbol->natural_name (), 0,
- NULL, 0) == 0)
- {
- /* For functions we can do a quick check of whether the
- symbol might be found via find_pc_symtab. */
- if (kind != FUNCTIONS_DOMAIN
- || (find_pc_compunit_symtab
- (MSYMBOL_VALUE_ADDRESS (objfile, msymbol))
- == NULL))
- {
- if (lookup_symbol_in_objfile_from_linkage_name
- (objfile, msymbol->linkage_name (), VAR_DOMAIN)
- .symbol == NULL)
- {
- /* match */
- result.emplace_back (i, msymbol, objfile);
- }
- }
- }
- }
- }
- }
+ if (!add_matching_msymbols (objfile, preg, &result))
+ break;
}
return result;
}
-/* Helper function for symtab_symbol_info, this function uses
- the data returned from search_symbols() to print information
- regarding the match to gdb_stdout. If LAST is not NULL,
- print file and line number information for the symbol as
- well. Skip printing the filename if it matches LAST. */
+/* See symtab.h. */
-static void
-print_symbol_info (enum search_domain kind,
- struct symbol *sym,
- int block, const char *last)
+std::string
+symbol_to_info_string (struct symbol *sym, int block,
+ enum search_domain kind)
{
- scoped_switch_to_sym_language_if_auto l (sym);
- struct symtab *s = symbol_symtab (sym);
-
- if (last != NULL)
- {
- const char *s_filename = symtab_to_filename_for_display (s);
-
- if (filename_cmp (last, s_filename) != 0)
- {
- printf_filtered (_("\nFile %ps:\n"),
- styled_string (file_name_style.style (),
- s_filename));
- }
+ std::string str;
- if (SYMBOL_LINE (sym) != 0)
- printf_filtered ("%d:\t", SYMBOL_LINE (sym));
- else
- puts_filtered ("\t");
- }
+ gdb_assert (block == GLOBAL_BLOCK || block == STATIC_BLOCK);
if (kind != TYPES_DOMAIN && block == STATIC_BLOCK)
- printf_filtered ("static ");
+ str += "static ";
/* Typedef that is not a C++ class. */
if (kind == TYPES_DOMAIN
&& SYMBOL_DOMAIN (sym) != STRUCT_DOMAIN)
{
+ string_file tmp_stream;
+
/* FIXME: For C (and C++) we end up with a difference in output here
between how a typedef is printed, and non-typedefs are printed.
The TYPEDEF_PRINT code places a ";" at the end in an attempt to
printing of the ";" in this function, which is going to be wrong
for languages that don't require a ";" between statements. */
if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_TYPEDEF)
- typedef_print (SYMBOL_TYPE (sym), sym, gdb_stdout);
+ typedef_print (SYMBOL_TYPE (sym), sym, &tmp_stream);
else
- type_print (SYMBOL_TYPE (sym), "", gdb_stdout, -1);
- printf_filtered ("\n");
+ type_print (SYMBOL_TYPE (sym), "", &tmp_stream, -1);
+ str += tmp_stream.string ();
}
/* variable, func, or typedef-that-is-c++-class. */
else if (kind < TYPES_DOMAIN
|| (kind == TYPES_DOMAIN
&& SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN))
{
+ string_file tmp_stream;
+
type_print (SYMBOL_TYPE (sym),
(SYMBOL_CLASS (sym) == LOC_TYPEDEF
? "" : sym->print_name ()),
- gdb_stdout, 0);
+ &tmp_stream, 0);
- printf_filtered (";\n");
+ str += tmp_stream.string ();
+ str += ";";
}
/* Printing of modules is currently done here, maybe at some future
point we might want a language specific method to print the module
symbol so that we can customise the output more. */
else if (kind == MODULES_DOMAIN)
- printf_filtered ("%s\n", sym->print_name ());
+ str += sym->print_name ();
+
+ return str;
+}
+
+/* Helper function for symbol info commands, for example 'info functions',
+ 'info variables', etc. KIND is the kind of symbol we searched for, and
+ BLOCK is the type of block the symbols was found in, either GLOBAL_BLOCK
+ or STATIC_BLOCK. SYM is the symbol we found. If LAST is not NULL,
+ print file and line number information for the symbol as well. Skip
+ printing the filename if it matches LAST. */
+
+static void
+print_symbol_info (enum search_domain kind,
+ struct symbol *sym,
+ int block, const char *last)
+{
+ scoped_switch_to_sym_language_if_auto l (sym);
+ struct symtab *s = symbol_symtab (sym);
+
+ if (last != NULL)
+ {
+ const char *s_filename = symtab_to_filename_for_display (s);
+
+ if (filename_cmp (last, s_filename) != 0)
+ {
+ printf_filtered (_("\nFile %ps:\n"),
+ styled_string (file_name_style.style (),
+ s_filename));
+ }
+
+ if (SYMBOL_LINE (sym) != 0)
+ printf_filtered ("%d:\t", SYMBOL_LINE (sym));
+ else
+ puts_filtered ("\t");
+ }
+
+ std::string str = symbol_to_info_string (sym, block, kind);
+ printf_filtered ("%s\n", str.c_str ());
}
/* This help function for symtab_symbol_info() prints information
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)
{
and 'info functions' commands. These correspond to the -q, -t, and -n
options. */
-struct info_print_options
+struct info_vars_funcs_options
{
bool quiet = false;
bool exclude_minsyms = false;
char *type_regexp = nullptr;
- ~info_print_options ()
+ ~info_vars_funcs_options ()
{
xfree (type_regexp);
}
/* The options used by the 'info variables' and 'info functions'
commands. */
-static const gdb::option::option_def info_print_options_defs[] = {
- gdb::option::boolean_option_def<info_print_options> {
+static const gdb::option::option_def info_vars_funcs_options_defs[] = {
+ gdb::option::boolean_option_def<info_vars_funcs_options> {
"q",
- [] (info_print_options *opt) { return &opt->quiet; },
+ [] (info_vars_funcs_options *opt) { return &opt->quiet; },
nullptr, /* show_cmd_cb */
nullptr /* set_doc */
},
- gdb::option::boolean_option_def<info_print_options> {
+ gdb::option::boolean_option_def<info_vars_funcs_options> {
"n",
- [] (info_print_options *opt) { return &opt->exclude_minsyms; },
+ [] (info_vars_funcs_options *opt) { return &opt->exclude_minsyms; },
nullptr, /* show_cmd_cb */
nullptr /* set_doc */
},
- gdb::option::string_option_def<info_print_options> {
+ gdb::option::string_option_def<info_vars_funcs_options> {
"t",
- [] (info_print_options *opt) { return &opt->type_regexp; },
+ [] (info_vars_funcs_options *opt) { return &opt->type_regexp;
+ },
nullptr, /* show_cmd_cb */
nullptr /* set_doc */
}
functions'. */
static gdb::option::option_def_group
-make_info_print_options_def_group (info_print_options *opts)
+make_info_vars_funcs_options_def_group (info_vars_funcs_options *opts)
{
- return {{info_print_options_defs}, opts};
+ return {{info_vars_funcs_options_defs}, opts};
}
/* Command completer for 'info variables' and 'info functions'. */
static void
-info_print_command_completer (struct cmd_list_element *ignore,
- completion_tracker &tracker,
- const char *text, const char * /* word */)
+info_vars_funcs_command_completer (struct cmd_list_element *ignore,
+ completion_tracker &tracker,
+ const char *text, const char * /* word */)
{
const auto group
- = make_info_print_options_def_group (nullptr);
+ = make_info_vars_funcs_options_def_group (nullptr);
if (gdb::option::complete_options
(tracker, &text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, group))
return;
static void
info_variables_command (const char *args, int from_tty)
{
- info_print_options opts;
- auto grp = make_info_print_options_def_group (&opts);
+ info_vars_funcs_options opts;
+ auto grp = make_info_vars_funcs_options_def_group (&opts);
gdb::option::process_options
(&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, grp);
if (args != nullptr && *args == '\0')
static void
info_functions_command (const char *args, int from_tty)
{
- info_print_options opts;
- auto grp = make_info_print_options_def_group (&opts);
+ info_vars_funcs_options opts;
+
+ auto grp = make_info_vars_funcs_options_def_group (&opts);
gdb::option::process_options
(&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, grp);
if (args != nullptr && *args == '\0')
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, ':');
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)
const lookup_name_info &lookup_name,
const char *text, const char *word)
{
- completion_list_add_name (tracker, SYMBOL_LANGUAGE (sym),
+ completion_list_add_name (tracker, sym->language (),
sym->natural_name (),
lookup_name, text, word);
}
const lookup_name_info &lookup_name,
const char *text, const char *word)
{
- completion_list_add_name (tracker, MSYMBOL_LANGUAGE (sym),
+ completion_list_add_name (tracker, sym->language (),
sym->natural_name (),
lookup_name, text, word);
}
if (c == TYPE_CODE_UNION || c == TYPE_CODE_STRUCT)
for (j = TYPE_N_BASECLASSES (t); j < TYPE_NFIELDS (t); j++)
if (TYPE_FIELD_NAME (t, j))
- completion_list_add_name (tracker, SYMBOL_LANGUAGE (sym),
+ completion_list_add_name (tracker, sym->language (),
TYPE_FIELD_NAME (t, j),
lookup_name, text, word);
}
return BMSYMBOL_VALUE_ADDRESS (found);
}
}
- return (minsym->value.address
- + ANOFFSET (objf->section_offsets, minsym->section));
+ return minsym->value.address + objf->section_offsets[minsym->section];
}
\f
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. */
\f
+void _initialize_symtab ();
void
-_initialize_symtab (void)
+_initialize_symtab ()
{
cmd_list_element *c;
Prints the global and static variables.\n"),
_("global and static variables"),
true));
- set_cmd_completer_handle_brkchars (c, info_print_command_completer);
+ set_cmd_completer_handle_brkchars (c, info_vars_funcs_command_completer);
if (dbx_commands)
{
c = add_com ("whereis", class_info, info_variables_command,
Prints the global and static variables.\n"),
_("global and static variables"),
true));
- set_cmd_completer_handle_brkchars (c, info_print_command_completer);
+ set_cmd_completer_handle_brkchars (c, info_vars_funcs_command_completer);
}
c = add_info ("functions", info_functions_command,
Prints the functions.\n"),
_("functions"),
true));
- set_cmd_completer_handle_brkchars (c, info_print_command_completer);
+ set_cmd_completer_handle_brkchars (c, info_vars_funcs_command_completer);
c = add_info ("types", info_types_command, _("\
All type names, or those matching REGEXP.\n\