/* 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;
case VARIABLES_DOMAIN: return "VARIABLES_DOMAIN";
case FUNCTIONS_DOMAIN: return "FUNCTIONS_DOMAIN";
case TYPES_DOMAIN: return "TYPES_DOMAIN";
+ case MODULES_DOMAIN: return "MODULES_DOMAIN";
case ALL_DOMAIN: return "ALL_DOMAIN";
default: gdb_assert_not_reached ("bad search_domain");
}
gdb_assert (IS_ABSOLUTE_PATH (real_path));
gdb_assert (IS_ABSOLUTE_PATH (name));
+ gdb::unique_xmalloc_ptr<char> fullname_real_path
+ = gdb_realpath (fullname);
+ fullname = fullname_real_path.get ();
if (FILENAME_CMP (real_path, fullname) == 0)
{
if (callback (s))
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));
}
}
: mangled (mangled_name) {}
gdb::string_view mangled;
- ENUM_BITFIELD(language) language : LANGUAGE_BITS;
- char demangled[1];
+ enum language language;
+ gdb::unique_xmalloc_ptr<char> demangled;
};
/* Hash function for the demangled name hash. */
/* Choose 256 as the starting size of the hash table, somewhat arbitrarily.
The hash table code will round this up to the next prime number.
Choosing a much larger table size wastes memory, and saves only about
- 1% in symbol reading. */
+ 1% in symbol reading. However, if the minsym count is already
+ initialized (e.g. because symbol name setting was deferred to
+ a background thread) we can initialize the hashtable with a count
+ based on that, because we will almost certainly have at least that
+ many entries. If we have a nonzero number but less than 256,
+ we still stay with 256 to have some space for psymbols, etc. */
+
+ /* htab will expand the table when it is 3/4th full, so we account for that
+ here. +2 to round up. */
+ int minsym_based_count = (per_bfd->minimal_symbol_count + 2) / 3 * 4;
+ int count = std::max (per_bfd->minimal_symbol_count, minsym_based_count);
per_bfd->demangled_names_hash.reset (htab_create_alloc
- (256, hash_demangled_name_entry, eq_demangled_name_entry,
+ (count, hash_demangled_name_entry, eq_demangled_name_entry,
free_demangled_name_entry, xcalloc, xfree));
}
-/* Try to determine the demangled name for a symbol, based on the
- language of that symbol. If the language is set to language_auto,
- it will attempt to find any demangling algorithm that works and
- then set the language appropriately. The returned name is allocated
- by the demangler and should be xfree'd. */
+/* See symtab.h */
-static char *
+char *
symbol_find_demangled_name (struct general_symbol_info *gsymbol,
const char *mangled)
{
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,
- const char *linkage_name, int len, 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;
- /* A 0-terminated copy of the linkage name. */
- const char *linkage_name_copy;
- 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;
+ m_name = linkage_name.data ();
else
- {
- char *name = (char *) obstack_alloc (&per_bfd->storage_obstack,
- len + 1);
-
- memcpy (name, linkage_name, len);
- name[len] = '\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;
}
if (per_bfd->demangled_names_hash == NULL)
create_demangled_names_hash (per_bfd);
- if (linkage_name[len] != '\0')
- {
- char *alloc_name;
-
- alloc_name = (char *) alloca (len + 1);
- memcpy (alloc_name, linkage_name, len);
- alloc_name[len] = '\0';
-
- linkage_name_copy = alloc_name;
- }
- else
- linkage_name_copy = linkage_name;
-
- struct demangled_name_entry entry (gdb::string_view (linkage_name_copy, len));
+ 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[0] == '\0'))
+ || (language () == language_go && (*slot)->demangled == nullptr))
{
- char *demangled_name_ptr
- = symbol_find_demangled_name (gsymbol, linkage_name_copy);
- gdb::unique_xmalloc_ptr<char> demangled_name (demangled_name_ptr);
- int demangled_len = demangled_name ? strlen (demangled_name.get ()) : 0;
+ /* 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
+ this copy because demangling needs a nullterminated string. */
+ gdb::string_view linkage_name_copy;
+ if (copy_name)
+ {
+ char *alloc_name = (char *) alloca (linkage_name.length () + 1);
+ memcpy (alloc_name, linkage_name.data (), linkage_name.length ());
+ alloc_name[linkage_name.length ()] = '\0';
+
+ linkage_name_copy = gdb::string_view (alloc_name,
+ linkage_name.length ());
+ }
+ else
+ linkage_name_copy = linkage_name;
+
+ 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
mangled name saved, and we don't have a demangled name. So,
you might think we could save a little space by not recording
this in the hash table at all.
-
+
It turns out that it is actually important to still save such
an entry in the hash table, because storing this name gives
us better bcache hit rates for partial symbols. */
- if (!copy_name && linkage_name_copy == linkage_name)
+ if (!copy_name)
{
*slot
= ((struct demangled_name_entry *)
obstack_alloc (&per_bfd->storage_obstack,
- offsetof (struct demangled_name_entry, demangled)
- + demangled_len + 1));
- new (*slot) demangled_name_entry
- (gdb::string_view (linkage_name, len));
+ sizeof (demangled_name_entry)));
+ new (*slot) demangled_name_entry (linkage_name);
}
else
{
- char *mangled_ptr;
-
/* If we must copy the mangled name, put it directly after
- the demangled name so we can have a single
- allocation. */
+ the struct so we can have a single allocation. */
*slot
= ((struct demangled_name_entry *)
obstack_alloc (&per_bfd->storage_obstack,
- offsetof (struct demangled_name_entry, demangled)
- + len + demangled_len + 2));
- mangled_ptr = &((*slot)->demangled[demangled_len + 1]);
- strcpy (mangled_ptr, linkage_name_copy);
+ sizeof (demangled_name_entry)
+ + linkage_name.length () + 1));
+ char *mangled_ptr = reinterpret_cast<char *> (*slot + 1);
+ memcpy (mangled_ptr, linkage_name.data (), linkage_name.length ());
+ mangled_ptr [linkage_name.length ()] = '\0';
new (*slot) demangled_name_entry
- (gdb::string_view (mangled_ptr, len));
+ (gdb::string_view (mangled_ptr, linkage_name.length ()));
}
- (*slot)->language = gsymbol->language;
-
- if (demangled_name != NULL)
- strcpy ((*slot)->demangled, demangled_name.get ());
- else
- (*slot)->demangled[0] = '\0';
+ (*slot)->demangled = std::move (demangled_name);
+ (*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[0] != '\0')
- symbol_set_demangled_name (gsymbol, (*slot)->demangled,
- &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);
}
-/* Return the source code name of a symbol. In languages where
- demangling is necessary, this is the demangled name. */
+/* See symtab.h. */
const char *
-symbol_natural_name (const struct general_symbol_info *gsymbol)
+general_symbol_info::natural_name () const
{
- switch (gsymbol->language)
+ switch (language ())
{
case language_cplus:
case language_d:
case language_go:
case language_objc:
case language_fortran:
- if (symbol_get_demangled_name (gsymbol) != NULL)
- return symbol_get_demangled_name (gsymbol);
+ if (symbol_get_demangled_name (this) != NULL)
+ return symbol_get_demangled_name (this);
break;
case language_ada:
- return ada_decode_symbol (gsymbol);
+ return ada_decode_symbol (this);
default:
break;
}
- return gsymbol->name;
+ return linkage_name ();
}
-/* Return the demangled name for a symbol based on the language for
- that symbol. If no demangled name exists, return NULL. */
+/* See symtab.h. */
const char *
-symbol_demangled_name (const struct general_symbol_info *gsymbol)
+general_symbol_info::demangled_name () const
{
const char *dem_name = NULL;
- switch (gsymbol->language)
+ switch (language ())
{
case language_cplus:
case language_d:
case language_go:
case language_objc:
case language_fortran:
- dem_name = symbol_get_demangled_name (gsymbol);
+ dem_name = symbol_get_demangled_name (this);
break;
case language_ada:
- dem_name = ada_decode_symbol (gsymbol);
+ dem_name = ada_decode_symbol (this);
break;
default:
break;
return dem_name;
}
-/* Return the search name of a symbol---generally the demangled or
- linkage name of the symbol, depending on how it will be searched for.
- If there is no distinct demangled name, then returns the same value
- (same pointer) as SYMBOL_LINKAGE_NAME. */
+/* See symtab.h. */
const char *
-symbol_search_name (const struct general_symbol_info *gsymbol)
+general_symbol_info::search_name () const
{
- if (gsymbol->language == language_ada)
- return gsymbol->name;
+ if (language () == language_ada)
+ return linkage_name ();
else
- return symbol_natural_name (gsymbol);
+ return natural_name ();
}
/* See symtab.h. */
const lookup_name_info &name)
{
symbol_name_matcher_ftype *name_match
- = get_symbol_name_matcher (language_def (gsymbol->language), name);
- return name_match (symbol_search_name (gsymbol), name, NULL);
+ = get_symbol_name_matcher (language_def (gsymbol->language ()), name);
+ return name_match (gsymbol->search_name (), name, NULL);
}
\f
}
else
{
- slot_name = SYMBOL_SEARCH_NAME (slot->value.found.symbol);
+ slot_name = slot->value.found.symbol->search_name ();
slot_domain = SYMBOL_DOMAIN (slot->value.found.symbol);
}
/* It's important that we use the same comparison that was done
the first time through. If the slot records a found symbol,
then this means using the symbol name comparison function of
- the symbol's language with SYMBOL_SEARCH_NAME. See
+ the symbol's language with symbol->search_name (). See
dictionary.c. It also means using symbol_matches_domain for
found symbols. See block.c.
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*
printf_filtered (" [%4u] = %s, %s %s\n", i,
host_address_to_string (context),
- SYMBOL_PRINT_NAME (found),
+ found->print_name (),
domain_name (SYMBOL_DOMAIN (found)));
break;
}
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;
return sym;
}
- fixup_section (&sym->ginfo, addr, objfile);
+ fixup_section (sym, addr, objfile);
return sym;
}
if (symbol_lookup_debug > 1)
{
fprintf_unfiltered (gdb_stdlog, " = %s (%s, block %s)\n",
- SYMBOL_PRINT_NAME (sym),
+ sym->print_name (),
host_address_to_string (sym),
host_address_to_string (block));
}
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};
if (MSYMBOL_TYPE (msymbol.minsym) == mst_solib_trampoline)
{
struct bound_minimal_symbol mfunsym
- = lookup_minimal_symbol_text (MSYMBOL_LINKAGE_NAME (msymbol.minsym),
+ = lookup_minimal_symbol_text (msymbol.minsym->linkage_name (),
NULL);
if (mfunsym.minsym == NULL)
* but the "break" still works, and the warning is annoying.
* So I commented out the warning. RT */
/* warning ("In stub for %s; unable to find real function/line info",
- SYMBOL_LINKAGE_NAME (msymbol)); */
+ msymbol->linkage_name ()); */
;
/* fall through */
else if (BMSYMBOL_VALUE_ADDRESS (mfunsym)
/* Avoid infinite recursion */
/* See above comment about why warning is commented out. */
/* warning ("In stub for %s; unable to find real function/line info",
- SYMBOL_LINKAGE_NAME (msymbol)); */
+ msymbol->linkage_name ()); */
;
/* fall through */
else
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
objfile = symbol_objfile (sym);
pc = BLOCK_ENTRY_PC (SYMBOL_BLOCK_VALUE (sym));
section = SYMBOL_OBJ_SECTION (objfile, sym);
- name = SYMBOL_LINKAGE_NAME (sym);
+ name = sym->linkage_name ();
}
else
{
objfile = msymbol.objfile;
pc = BMSYMBOL_VALUE_ADDRESS (msymbol);
section = MSYMBOL_OBJ_SECTION (objfile, msymbol.minsym);
- name = MSYMBOL_LINKAGE_NAME (msymbol.minsym);
+ name = msymbol.minsym->linkage_name ();
}
gdbarch = get_objfile_arch (objfile);
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,
if (sym_a.block != sym_b.block)
return sym_a.block - sym_b.block;
- return strcmp (SYMBOL_PRINT_NAME (sym_a.symbol),
- SYMBOL_PRINT_NAME (sym_b.symbol));
+ return strcmp (sym_a.symbol->print_name (), sym_b.symbol->print_name ());
}
/* Returns true if the type_name of symbol_type of SYM matches TREG.
{
fprintf_unfiltered (gdb_stdlog,
"treg_matches_sym_type_name\n sym %s\n",
- SYMBOL_NATURAL_NAME (sym));
+ sym->natural_name ());
}
sym_type = SYMBOL_TYPE (sym);
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;
+ }
+}
+
+/* See symtab.h. */
-/* Sort the symbols in RESULT and remove duplicates. */
+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;
-static void
-sort_search_symbols_remove_dups (std::vector<symbol_search> *result)
+ 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;
+
+ for (minimal_symbol *msymbol : objfile->msymbols ())
+ {
+ QUIT;
+
+ if (msymbol->created_by_gdb)
+ continue;
- 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
+ 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 <= TYPES_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 (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;
- }
- }
- }
- }
+ 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 (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))))
- {
- /* 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 (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 (!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);
+ std::string str;
- 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");
- }
+ 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
- ? "" : SYMBOL_PRINT_NAME (sym)),
- gdb_stdout, 0);
+ ? "" : sym->print_name ()),
+ &tmp_stream, 0);
+
+ 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)
+ 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));
+ }
- printf_filtered (";\n");
+ 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
printf_filtered (_("%ps %ps\n"),
styled_string (address_style.style (), tmp),
- styled_string (sym_style,
- MSYMBOL_PRINT_NAME (msymbol.minsym)));
+ styled_string (sym_style, msymbol.minsym->print_name ()));
}
/* This is the guts of the commands "info functions", "info types", and
const char *t_regexp, int from_tty)
{
static const char * const classnames[] =
- {"variable", "function", "type"};
+ {"variable", "function", "type", "module"};
const char *last_filename = "";
int first = 1;
- gdb_assert (kind <= TYPES_DOMAIN);
+ gdb_assert (kind != ALL_DOMAIN);
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')
symbol_completer (ignore, tracker, text, word);
}
-/* Breakpoint all functions matching regular expression. */
+/* Implement the 'info modules' command. */
-void
-rbreak_command_wrapper (char *regexp, int from_tty)
+static void
+info_modules_command (const char *args, int from_tty)
{
- rbreak_command (regexp, from_tty);
+ info_types_options opts;
+
+ auto grp = make_info_types_options_def_group (&opts);
+ gdb::option::process_options
+ (&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, grp);
+ if (args != nullptr && *args == '\0')
+ args = nullptr;
+ symtab_symbol_info (opts.quiet, true, args, MODULES_DOMAIN, NULL,
+ from_tty);
}
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, ':');
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 char *fullname = symtab_to_fullname (symtab);
string = string_printf ("%s:'%s'", fullname,
- SYMBOL_LINKAGE_NAME (p.symbol));
+ p.symbol->linkage_name ());
break_command (&string[0], from_tty);
print_symbol_info (FUNCTIONS_DOMAIN, p.symbol, p.block, NULL);
}
else
{
string = string_printf ("'%s'",
- MSYMBOL_LINKAGE_NAME (p.msymbol.minsym));
+ p.msymbol.minsym->linkage_name ());
break_command (&string[0], from_tty);
printf_filtered ("<function, no debug info> %s;\n",
- MSYMBOL_PRINT_NAME (p.msymbol.minsym));
+ p.msymbol.minsym->print_name ());
}
}
}
const lookup_name_info &lookup_name,
const char *text, const char *word)
{
- completion_list_add_name (tracker, SYMBOL_LANGUAGE (sym),
- SYMBOL_NATURAL_NAME (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),
- MSYMBOL_NATURAL_NAME (sym),
+ completion_list_add_name (tracker, sym->language (),
+ sym->natural_name (),
lookup_name, text, word);
}
const char *method, *category, *selector;
char *tmp2 = NULL;
- method = MSYMBOL_NATURAL_NAME (msymbol);
+ method = msymbol->natural_name ();
/* Is it a method? */
if ((method[0] != '-') && (method[0] != '+'))
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);
}
if (SYMBOL_CLASS (sym) != LOC_BLOCK)
return {};
- lookup_name_info lookup_name (SYMBOL_SEARCH_NAME (sym),
+ lookup_name_info lookup_name (sym->search_name (),
symbol_name_match_type::SEARCH_NAME);
struct objfile *objfile = symbol_objfile (sym);
\f
-/* Helper function to initialize the fields of an objfile-owned symbol.
- It assumed that *SYM is already all zeroes. */
-
-static void
-initialize_objfile_symbol_1 (struct symbol *sym)
-{
- SYMBOL_OBJFILE_OWNED (sym) = 1;
- SYMBOL_SECTION (sym) = -1;
-}
-
/* Initialize the symbol SYM, and mark it as being owned by an objfile. */
void
initialize_objfile_symbol (struct symbol *sym)
{
- memset (sym, 0, sizeof (*sym));
- initialize_objfile_symbol_1 (sym);
+ SYMBOL_OBJFILE_OWNED (sym) = 1;
+ SYMBOL_SECTION (sym) = -1;
}
/* Allocate and initialize a new 'struct symbol' on OBJFILE's
struct symbol *
allocate_symbol (struct objfile *objfile)
{
- struct symbol *result;
+ struct symbol *result = new (&objfile->objfile_obstack) symbol ();
- result = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct symbol);
- initialize_objfile_symbol_1 (result);
+ initialize_objfile_symbol (result);
return result;
}
{
struct template_symbol *result;
- result = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct template_symbol);
- initialize_objfile_symbol_1 (result);
+ result = new (&objfile->objfile_obstack) template_symbol ();
+ initialize_objfile_symbol (result);
return result;
}
gdb_assert (sym->maybe_copied);
gdb_assert (SYMBOL_CLASS (sym) == LOC_STATIC);
- const char *linkage_name = SYMBOL_LINKAGE_NAME (sym);
+ const char *linkage_name = sym->linkage_name ();
for (objfile *objfile : current_program_space->objfiles ())
{
if (minsym.minsym != nullptr)
return BMSYMBOL_VALUE_ADDRESS (minsym);
}
- return sym->ginfo.value.address;
+ return sym->value.address;
}
/* See symtab.h. */
gdb_assert (minsym->maybe_copied);
gdb_assert ((objf->flags & OBJF_MAINLINE) == 0);
- const char *linkage_name = MSYMBOL_LINKAGE_NAME (minsym);
+ const char *linkage_name = minsym->linkage_name ();
for (objfile *objfile : current_program_space->objfiles ())
{
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
+/* Hold the sub-commands of 'info module'. */
+
+static struct cmd_list_element *info_module_cmdlist = NULL;
+
+/* Implement the 'info module' command, just displays some help text for
+ the available sub-commands. */
+
+static void
+info_module_command (const char *args, int from_tty)
+{
+ help_list (info_module_cmdlist, "info module ", class_info, gdb_stdout);
+}
+
+/* See symtab.h. */
+
+std::vector<module_symbol_search>
+search_module_symbols (const char *module_regexp, const char *regexp,
+ const char *type_regexp, search_domain kind)
+{
+ std::vector<module_symbol_search> results;
+
+ /* Search for all modules matching MODULE_REGEXP. */
+ 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. */
+ 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. */
+ for (const symbol_search &p : modules)
+ {
+ QUIT;
+
+ /* This is a module. */
+ gdb_assert (p.symbol != nullptr);
+
+ std::string prefix = p.symbol->print_name ();
+ prefix += "::";
+
+ for (const symbol_search &q : symbols)
+ {
+ if (q.symbol == nullptr)
+ continue;
+
+ if (strncmp (q.symbol->print_name (), prefix.c_str (),
+ prefix.size ()) != 0)
+ continue;
+
+ results.push_back ({p, q});
+ }
+ }
+
+ return results;
+}
+
+/* Implement the core of both 'info module functions' and 'info module
+ variables'. */
+
+static void
+info_module_subcommand (bool quiet, const char *module_regexp,
+ const char *regexp, const char *type_regexp,
+ search_domain kind)
+{
+ /* Print a header line. Don't build the header line bit by bit as this
+ prevents internationalisation. */
+ if (!quiet)
+ {
+ if (module_regexp == nullptr)
+ {
+ if (type_regexp == nullptr)
+ {
+ if (regexp == nullptr)
+ printf_filtered ((kind == VARIABLES_DOMAIN
+ ? _("All variables in all modules:")
+ : _("All functions in all modules:")));
+ else
+ printf_filtered
+ ((kind == VARIABLES_DOMAIN
+ ? _("All variables matching regular expression"
+ " \"%s\" in all modules:")
+ : _("All functions matching regular expression"
+ " \"%s\" in all modules:")),
+ regexp);
+ }
+ else
+ {
+ if (regexp == nullptr)
+ printf_filtered
+ ((kind == VARIABLES_DOMAIN
+ ? _("All variables with type matching regular "
+ "expression \"%s\" in all modules:")
+ : _("All functions with type matching regular "
+ "expression \"%s\" in all modules:")),
+ type_regexp);
+ else
+ printf_filtered
+ ((kind == VARIABLES_DOMAIN
+ ? _("All variables matching regular expression "
+ "\"%s\",\n\twith type matching regular "
+ "expression \"%s\" in all modules:")
+ : _("All functions matching regular expression "
+ "\"%s\",\n\twith type matching regular "
+ "expression \"%s\" in all modules:")),
+ regexp, type_regexp);
+ }
+ }
+ else
+ {
+ if (type_regexp == nullptr)
+ {
+ if (regexp == nullptr)
+ printf_filtered
+ ((kind == VARIABLES_DOMAIN
+ ? _("All variables in all modules matching regular "
+ "expression \"%s\":")
+ : _("All functions in all modules matching regular "
+ "expression \"%s\":")),
+ module_regexp);
+ else
+ printf_filtered
+ ((kind == VARIABLES_DOMAIN
+ ? _("All variables matching regular expression "
+ "\"%s\",\n\tin all modules matching regular "
+ "expression \"%s\":")
+ : _("All functions matching regular expression "
+ "\"%s\",\n\tin all modules matching regular "
+ "expression \"%s\":")),
+ regexp, module_regexp);
+ }
+ else
+ {
+ if (regexp == nullptr)
+ printf_filtered
+ ((kind == VARIABLES_DOMAIN
+ ? _("All variables with type matching regular "
+ "expression \"%s\"\n\tin all modules matching "
+ "regular expression \"%s\":")
+ : _("All functions with type matching regular "
+ "expression \"%s\"\n\tin all modules matching "
+ "regular expression \"%s\":")),
+ type_regexp, module_regexp);
+ else
+ printf_filtered
+ ((kind == VARIABLES_DOMAIN
+ ? _("All variables matching regular expression "
+ "\"%s\",\n\twith type matching regular expression "
+ "\"%s\",\n\tin all modules matching regular "
+ "expression \"%s\":")
+ : _("All functions matching regular expression "
+ "\"%s\",\n\twith type matching regular expression "
+ "\"%s\",\n\tin all modules matching regular "
+ "expression \"%s\":")),
+ regexp, type_regexp, module_regexp);
+ }
+ }
+ printf_filtered ("\n");
+ }
+
+ /* Find all symbols of type KIND matching the given regular expressions
+ along with the symbols for the modules in which those symbols
+ reside. */
+ std::vector<module_symbol_search> module_symbols
+ = search_module_symbols (module_regexp, regexp, type_regexp, kind);
+
+ std::sort (module_symbols.begin (), module_symbols.end (),
+ [] (const module_symbol_search &a, const module_symbol_search &b)
+ {
+ if (a.first < b.first)
+ return true;
+ else if (a.first == b.first)
+ return a.second < b.second;
+ else
+ return false;
+ });
+
+ const char *last_filename = "";
+ const symbol *last_module_symbol = nullptr;
+ for (const module_symbol_search &ms : module_symbols)
+ {
+ const symbol_search &p = ms.first;
+ const symbol_search &q = ms.second;
+
+ gdb_assert (q.symbol != nullptr);
+
+ if (last_module_symbol != p.symbol)
+ {
+ printf_filtered ("\n");
+ printf_filtered (_("Module \"%s\":\n"), p.symbol->print_name ());
+ last_module_symbol = p.symbol;
+ last_filename = "";
+ }
+
+ print_symbol_info (FUNCTIONS_DOMAIN, q.symbol, q.block,
+ last_filename);
+ last_filename
+ = symtab_to_filename_for_display (symbol_symtab (q.symbol));
+ }
+}
+
+/* Hold the option values for the 'info module .....' sub-commands. */
+
+struct info_modules_var_func_options
+{
+ bool quiet = false;
+ char *type_regexp = nullptr;
+ char *module_regexp = nullptr;
+
+ ~info_modules_var_func_options ()
+ {
+ xfree (type_regexp);
+ xfree (module_regexp);
+ }
+};
+
+/* The options used by 'info module variables' and 'info module functions'
+ commands. */
+
+static const gdb::option::option_def info_modules_var_func_options_defs [] = {
+ gdb::option::boolean_option_def<info_modules_var_func_options> {
+ "q",
+ [] (info_modules_var_func_options *opt) { return &opt->quiet; },
+ nullptr, /* show_cmd_cb */
+ nullptr /* set_doc */
+ },
+
+ gdb::option::string_option_def<info_modules_var_func_options> {
+ "t",
+ [] (info_modules_var_func_options *opt) { return &opt->type_regexp; },
+ nullptr, /* show_cmd_cb */
+ nullptr /* set_doc */
+ },
+
+ gdb::option::string_option_def<info_modules_var_func_options> {
+ "m",
+ [] (info_modules_var_func_options *opt) { return &opt->module_regexp; },
+ nullptr, /* show_cmd_cb */
+ nullptr /* set_doc */
+ }
+};
+
+/* Return the option group used by the 'info module ...' sub-commands. */
+
+static inline gdb::option::option_def_group
+make_info_modules_var_func_options_def_group
+ (info_modules_var_func_options *opts)
+{
+ return {{info_modules_var_func_options_defs}, opts};
+}
+
+/* Implements the 'info module functions' command. */
+
+static void
+info_module_functions_command (const char *args, int from_tty)
+{
+ info_modules_var_func_options opts;
+ auto grp = make_info_modules_var_func_options_def_group (&opts);
+ gdb::option::process_options
+ (&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, grp);
+ if (args != nullptr && *args == '\0')
+ args = nullptr;
+
+ info_module_subcommand (opts.quiet, opts.module_regexp, args,
+ opts.type_regexp, FUNCTIONS_DOMAIN);
+}
+
+/* Implements the 'info module variables' command. */
+
+static void
+info_module_variables_command (const char *args, int from_tty)
+{
+ info_modules_var_func_options opts;
+ auto grp = make_info_modules_var_func_options_def_group (&opts);
+ gdb::option::process_options
+ (&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, grp);
+ if (args != nullptr && *args == '\0')
+ args = nullptr;
+
+ info_module_subcommand (opts.quiet, opts.module_regexp, args,
+ opts.type_regexp, VARIABLES_DOMAIN);
+}
+
+/* Command completer for 'info module ...' sub-commands. */
+
+static void
+info_module_var_func_command_completer (struct cmd_list_element *ignore,
+ completion_tracker &tracker,
+ const char *text,
+ const char * /* word */)
+{
+
+ const auto group = make_info_modules_var_func_options_def_group (nullptr);
+ if (gdb::option::complete_options
+ (tracker, &text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, group))
+ return;
+
+ const char *word = advance_to_expression_complete_word_point (tracker, text);
+ symbol_completer (ignore, tracker, text, word);
+}
+
+\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\
c = add_info ("sources", info_sources_command, info_sources_help.c_str ());
set_cmd_completer_handle_brkchars (c, info_sources_command_completer);
+ c = add_info ("modules", info_modules_command,
+ _("All module names, or those matching REGEXP."));
+ set_cmd_completer_handle_brkchars (c, info_types_command_completer);
+
+ add_prefix_cmd ("module", class_info, info_module_command, _("\
+Print information about modules."),
+ &info_module_cmdlist, "info module ",
+ 0, &infolist);
+
+ c = add_cmd ("functions", class_info, info_module_functions_command, _("\
+Display functions arranged by modules.\n\
+Usage: info module functions [-q] [-m MODREGEXP] [-t TYPEREGEXP] [REGEXP]\n\
+Print a summary of all functions within each Fortran module, grouped by\n\
+module and file. For each function the line on which the function is\n\
+defined is given along with the type signature and name of the function.\n\
+\n\
+If REGEXP is provided then only functions whose name matches REGEXP are\n\
+listed. If MODREGEXP is provided then only functions in modules matching\n\
+MODREGEXP are listed. If TYPEREGEXP is given then only functions whose\n\
+type signature matches TYPEREGEXP are listed.\n\
+\n\
+The -q flag suppresses printing some header information."),
+ &info_module_cmdlist);
+ set_cmd_completer_handle_brkchars
+ (c, info_module_var_func_command_completer);
+
+ c = add_cmd ("variables", class_info, info_module_variables_command, _("\
+Display variables arranged by modules.\n\
+Usage: info module variables [-q] [-m MODREGEXP] [-t TYPEREGEXP] [REGEXP]\n\
+Print a summary of all variables within each Fortran module, grouped by\n\
+module and file. For each variable the line on which the variable is\n\
+defined is given along with the type and name of the variable.\n\
+\n\
+If REGEXP is provided then only variables whose name matches REGEXP are\n\
+listed. If MODREGEXP is provided then only variables in modules matching\n\
+MODREGEXP are listed. If TYPEREGEXP is given then only variables whose\n\
+type matches TYPEREGEXP are listed.\n\
+\n\
+The -q flag suppresses printing some header information."),
+ &info_module_cmdlist);
+ set_cmd_completer_handle_brkchars
+ (c, info_module_var_func_command_completer);
+
add_com ("rbreak", class_breakpoint, rbreak_command,
_("Set a breakpoint for all functions matching REGEXP."));