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::string_view mangled;
enum language language;
- char demangled[1];
+ 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));
}
void
symbol_set_names (struct general_symbol_info *gsymbol,
- const char *linkage_name, int len, bool copy_name,
+ gdb::string_view linkage_name, bool copy_name,
struct objfile_per_bfd_storage *per_bfd)
{
struct demangled_name_entry **slot;
- /* A 0-terminated copy of the linkage name. */
- const char *linkage_name_copy;
if (gsymbol->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;
+ gsymbol->name = linkage_name.data ();
else
{
char *name = (char *) obstack_alloc (&per_bfd->storage_obstack,
- len + 1);
+ linkage_name.length () + 1);
- memcpy (name, linkage_name, len);
- name[len] = '\0';
+ 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);
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);
slot = ((struct demangled_name_entry **)
htab_find_slot (per_bfd->demangled_names_hash.get (),
&entry, INSERT));
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'))
+ || (gsymbol->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;
+
+ gdb::unique_xmalloc_ptr<char> demangled_name_ptr
+ (symbol_find_demangled_name (gsymbol, 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)->demangled = std::move (demangled_name_ptr);
(*slot)->language = gsymbol->language;
-
- if (demangled_name != NULL)
- strcpy ((*slot)->demangled, demangled_name.get ());
- else
- (*slot)->demangled[0] = '\0';
}
else if (gsymbol->language == language_unknown
|| gsymbol->language == language_auto)
gsymbol->language = (*slot)->language;
gsymbol->name = (*slot)->mangled.data ();
- if ((*slot)->demangled[0] != '\0')
- symbol_set_demangled_name (gsymbol, (*slot)->demangled,
+ 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);
}
-/* 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 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 name;
else
- return symbol_natural_name (gsymbol);
+ return natural_name ();
}
/* See symtab.h. */
{
symbol_name_matcher_ftype *name_match
= get_symbol_name_matcher (language_def (gsymbol->language), name);
- return name_match (symbol_search_name (gsymbol), name, NULL);
+ return name_match (gsymbol->search_name (), name, NULL);
}
\f
return sym;
}
- fixup_section (&sym->ginfo, addr, objfile);
+ fixup_section (sym, addr, objfile);
return sym;
}
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)
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);
gdb::optional<compiled_regex> preg;
gdb::optional<compiled_regex> treg;
- gdb_assert (kind <= TYPES_DOMAIN);
+ gdb_assert (kind != ALL_DOMAIN);
ourtype = types[kind];
ourtype2 = types2[kind];
|| MSYMBOL_TYPE (msymbol) == ourtype4)
{
if (!preg.has_value ()
- || preg->exec (MSYMBOL_NATURAL_NAME (msymbol), 0,
+ || preg->exec (msymbol->natural_name (), 0,
NULL, 0) == 0)
{
/* Note: An important side-effect of these
(MSYMBOL_VALUE_ADDRESS (objfile, msymbol))
== NULL)
: (lookup_symbol_in_objfile_from_linkage_name
- (objfile, MSYMBOL_LINKAGE_NAME (msymbol),
- VAR_DOMAIN)
+ (objfile, msymbol->linkage_name (), VAR_DOMAIN)
.symbol == NULL))
found_misc = 1;
}
sym)))
|| (kind == TYPES_DOMAIN
&& SYMBOL_CLASS (sym) == LOC_TYPEDEF
- && SYMBOL_DOMAIN (sym) != MODULE_DOMAIN))))
+ && SYMBOL_DOMAIN (sym) != MODULE_DOMAIN)
+ || (kind == MODULES_DOMAIN
+ && SYMBOL_DOMAIN (sym) == MODULE_DOMAIN
+ && SYMBOL_LINE (sym) != 0))))
{
/* match */
result.emplace_back (i, sym);
|| MSYMBOL_TYPE (msymbol) == ourtype4)
{
if (!preg.has_value ()
- || preg->exec (MSYMBOL_NATURAL_NAME (msymbol), 0,
+ || preg->exec (msymbol->natural_name (), 0,
NULL, 0) == 0)
{
/* For functions we can do a quick check of whether the
== NULL))
{
if (lookup_symbol_in_objfile_from_linkage_name
- (objfile, MSYMBOL_LINKAGE_NAME (msymbol),
- VAR_DOMAIN)
+ (objfile, msymbol->linkage_name (), VAR_DOMAIN)
.symbol == NULL)
{
/* match */
if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_TYPEDEF)
typedef_print (SYMBOL_TYPE (sym), sym, gdb_stdout);
else
- {
- type_print (SYMBOL_TYPE (sym), "", gdb_stdout, -1);
- printf_filtered ("\n");
- }
+ type_print (SYMBOL_TYPE (sym), "", gdb_stdout, -1);
+ printf_filtered ("\n");
}
/* variable, func, or typedef-that-is-c++-class. */
else if (kind < TYPES_DOMAIN
printf_filtered (";\n");
}
+ /* 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", SYMBOL_PRINT_NAME (sym));
}
/* 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;
symbol_completer (ignore, tracker, text, word);
}
+/* Implement the 'info modules' command. */
+
+static void
+info_modules_command (const char *args, int 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);
+}
+
/* Breakpoint all functions matching regular expression. */
void
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 char *text, const char *word)
{
completion_list_add_name (tracker, MSYMBOL_LANGUAGE (sym),
- MSYMBOL_NATURAL_NAME (sym),
+ 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] != '+'))
\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;
}
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 ())
{
\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. */
+ std::vector<symbol_search> modules = search_symbols (module_regexp,
+ MODULES_DOMAIN,
+ NULL, 0, NULL,
+ true);
+
+ /* 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);
+
+ /* 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 = SYMBOL_PRINT_NAME (p.symbol);
+ prefix += "::";
+
+ for (const symbol_search &q : symbols)
+ {
+ if (q.symbol == nullptr)
+ continue;
+
+ if (strncmp (SYMBOL_PRINT_NAME (q.symbol), 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"),
+ SYMBOL_PRINT_NAME (p.symbol));
+ 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)
{
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."));