@@ -142,6 +142,20 @@ info modules [-q] [REGEXP]
Return a list of Fortran modules matching REGEXP, or all modules if
no REGEXP is given.
+info module functions [-q] [-m MODULE_REGEXP] [-t TYPE_REGEXP] [REGEXP]
+ Return a list of functions within all modules, grouped by module.
+ The list of functions can be restricted with the optional regular
+ expressions. MODULE_REGEXP matches against the module name,
+ TYPE_REGEXP matches against the function type signature, and REGEXP
+ matches against the function name.
+
+info module variables [-q] [-m MODULE_REGEXP] [-t TYPE_REGEXP] [REGEXP]
+ Return a list of variables within all modules, grouped by module.
+ The list of variables can be restricted with the optional regular
+ expressions. MODULE_REGEXP matches against the module name,
+ TYPE_REGEXP matches against the variable type, and REGEXP matches
+ against the variable name.
+
* Changed commands
help
@@ -18790,6 +18790,28 @@
printing header information and messages explaining why no modules
have been printed.
+@kindex info module functions
+@kindex info module variables
+@cindex modules
+@cindex functions
+@cindex variables
+@cindex module functions
+@cindex module variables
+@item info module functions [-q] [-m @var{module-regexp}] [-t @var{type-regexp}] [@var{regexp}]
+@item info module variables [-q] [-m @var{module-regexp}] [-t @var{type-regexp}] [@var{regexp}]
+List all functions or variables within all Fortran modules. The set
+of functions or variables listed can be limited by providing some or
+all of the optional regular expressions. If @var{module-regexp} is
+provided, then only Fortran modules matching @var{module-regexp} will
+be searched. Only functions or variables whose type matches the
+optional regular expression @var{type-regexp} will be listed. And
+only functions or variables whose name matches the optional regular
+expression @var{regexp} will be listed.
+
+The optional flag @samp{-q}, which stands for @samp{quiet}, disables
+printing header information and messages explaining why no functions
+or variables have been printed.
+
@kindex info classes
@cindex Objective-C, classes and selectors
@item info classes
@@ -6331,6 +6331,278 @@ get_msymbol_address (struct objfile *objf, const struct minimal_symbol *minsym)
+/* 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);
+}
+
+/* Implement the core of both 'info module functions' and 'info module
+ variables'. */
+
+static void
+info_module_subcommand_helper (bool quiet,
+ const char *module_regexp,
+ const char *regexp,
+ const char *type_regexp,
+ search_domain kind)
+{
+ /* Must make sure that if we're interrupted, MODULES gets freed. */
+ std::vector<symbol_search> modules = search_symbols (module_regexp,
+ MODULES_DOMAIN,
+ NULL, 0, NULL,
+ true);
+
+ /* 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");
+ }
+
+ /* 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 += "::";
+
+ bool module_header_printed = false;
+ const char *last_filename = "";
+ 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;
+
+ if (!module_header_printed)
+ {
+ printf_filtered ("\n");
+ printf_filtered (_("Module \"%s\":\n"),
+ SYMBOL_PRINT_NAME (p.symbol));
+ module_header_printed = true;
+ }
+
+ 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_helper (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_helper (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);
+}
+
+
+
void
_initialize_symtab (void)
{
@@ -6393,6 +6665,45 @@ Options:\n\
_("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."));
@@ -13,7 +13,8 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-# This file tests 'info modules'.
+# This file tests 'info modules', 'info module functions', and 'info
+# module variables'.
load_lib "fortran.exp"
@@ -30,13 +31,19 @@ if { ![runto MAIN__] } {
continue
}
+set logical4 [fortran_logical4]
+set integer4 [fortran_int4]
+set real4 [fortran_real4]
+
+# Test 'info modules' command.
+
gdb_test "info modules" \
[multi_line \
"All defined modules:" \
"" \
"File .*:" \
"16:\[\t \]+mod1" \
- "22:\[\t \]+mod2" ]
+ "37:\[\t \]+mod2" ]
gdb_test "info modules 1" \
[multi_line \
@@ -50,7 +57,7 @@ gdb_test "info modules 2" \
"All modules matching regular expression \"2\":" \
"" \
"File .*:" \
- "22:\[\t \]+mod2" ]
+ "37:\[\t \]+mod2" ]
gdb_test "info modules mod" \
[multi_line \
@@ -58,4 +65,117 @@ gdb_test "info modules mod" \
"" \
"File .*:" \
"16:\[\t \]+mod1" \
- "22:\[\t \]+mod2" ]
+ "37:\[\t \]+mod2" ]
+
+# Test 'info module functions'.
+
+gdb_test "info module functions" \
+ [multi_line \
+ "All functions in all modules:" \
+ "" \
+ "Module \"mod1\":" \
+ "" \
+ "File .*:" \
+ "35:\[\t \]+void mod1::__copy_mod1_M1t1\\(Type m1t1, Type m1t1\\);" \
+ "25:\[\t \]+void mod1::sub_m1_a\\(${integer4}\\);" \
+ "31:\[\t \]+${integer4} mod1::sub_m1_b\\(void\\);" \
+ "" \
+ "Module \"mod2\":" \
+ "" \
+ "File .*:" \
+ "41:\[\t \]+void mod2::sub_m2_a\\(${integer4}, ${logical4}\\);" \
+ "49:\[\t \]+${logical4} mod2::sub_m2_b\\(${real4}\\);" ]
+
+gdb_test "info module functions -m mod1" \
+ [multi_line \
+ "All functions in all modules matching regular expression \"mod1\":" \
+ "" \
+ "Module \"mod1\":" \
+ "" \
+ "File .*:" \
+ "35:\[\t \]+void mod1::__copy_mod1_M1t1\\(Type m1t1, Type m1t1\\);" \
+ "25:\[\t \]+void mod1::sub_m1_a\\(${integer4}\\);" \
+ "31:\[\t \]+${integer4} mod1::sub_m1_b\\(void\\);" ]
+
+gdb_test "info module functions -t integer" \
+ [multi_line \
+ "All functions with type matching regular expression \"integer\" in all modules:" \
+ "" \
+ "Module \"mod1\":" \
+ "" \
+ "File .*:" \
+ "25:\[\t \]+void mod1::sub_m1_a\\(${integer4}\\);" \
+ "31:\[\t \]+${integer4} mod1::sub_m1_b\\(void\\);" \
+ "" \
+ "Module \"mod2\":" \
+ "" \
+ "File .*:" \
+ "41:\[\t \]+void mod2::sub_m2_a\\(${integer4}, ${logical4}\\);" ]
+
+# Test 'info module variables'.
+
+gdb_test "info module variables" \
+ [multi_line \
+ "All variables in all modules:" \
+ "" \
+ "Module \"mod1\":" \
+ "" \
+ "File .*:" \
+ "35:\[\t \]+Type m1t1 mod1::__def_init_mod1_M1t1;" \
+ "35:\[\t \]+Type __vtype_mod1_M1t1 mod1::__vtab_mod1_M1t1;" \
+ "21:\[\t \]+${real4} mod1::mod1_var_1;" \
+ "22:\[\t \]+${integer4} mod1::mod1_var_2;" \
+ "" \
+ "Module \"mod2\":" \
+ "" \
+ "File .*:" \
+ "38:\[\t \]+${integer4} mod2::mod2_var_1;" \
+ "39:\[\t \]+${real4} mod2::mod2_var_2;" ]
+
+gdb_test "info module variables -t real" \
+ [multi_line \
+ "All variables with type matching regular expression \"real\" in all modules:" \
+ "" \
+ "Module \"mod1\":" \
+ "" \
+ "File .*:" \
+ "21:\[\t \]+${real4} mod1::mod1_var_1;" \
+ "" \
+ "Module \"mod2\":" \
+ "" \
+ "File .*:" \
+ "39:\[\t \]+${real4} mod2::mod2_var_2;" ]
+
+gdb_test "info module variables -m mod2" \
+ [multi_line \
+ "All variables in all modules matching regular expression \"mod2\":" \
+ "" \
+ "Module \"mod2\":" \
+ "" \
+ "File .*:" \
+ "38:\[\t \]+${integer4} mod2::mod2_var_1;" \
+ "39:\[\t \]+${real4} mod2::mod2_var_2;" ]
+
+gdb_test "info module variables -m mod2 -t real" \
+ [multi_line \
+ "All variables with type matching regular expression \"real\"" \
+ " in all modules matching regular expression \"mod2\":" \
+ "" \
+ "Module \"mod2\":" \
+ "" \
+ "File .*:" \
+ "39:\[\t \]+${real4} mod2::mod2_var_2;" ]
+
+gdb_test "info module variables _1" \
+ [multi_line \
+ "All variables matching regular expression \"_1\" in all modules:" \
+ "" \
+ "Module \"mod1\":" \
+ "" \
+ "File .*:" \
+ "21:\[\t \]+${real4} mod1::mod1_var_1;" \
+ "" \
+ "Module \"mod2\":" \
+ "" \
+ "File .*:" \
+ "38:\[\t \]+${integer4} mod2::mod2_var_1;" ]
@@ -34,6 +34,7 @@ set integer4 [fortran_int4]
set integer8 [fortran_int8]
set logical4 [fortran_logical4]
set character1 [fortran_character1]
+set real4 [fortran_real4]
gdb_test "info types" \
[multi_line \
@@ -44,7 +45,8 @@ gdb_test "info types" \
"\[\t \]+${integer4}" \
"(\[\t \]+${integer8}" \
")?\[\t \]+${logical4}" \
- "(20:\[\t \]+Type __vtype_mod1_M1t1;" \
+ "(35:\[\t \]+Type __vtype_mod1_M1t1;" \
")?$decimal:\[\t \]+Type m1t1;" \
- "26:\[\t \]+Type s1;(" \
+ "\[\t \]+${real4}" \
+ "57:\[\t \]+Type s1;(" \
".*)?"]
@@ -17,10 +17,41 @@ module mod1
type :: m1t1
integer :: b
end type m1t1
+
+ real :: mod1_var_1 = 1.0
+ integer, parameter :: mod1_var_2 = 456
+
+contains
+ subroutine sub_m1_a(arg)
+ integer :: arg
+ print*, "sub_m1_a"
+ print*, "arg = ", arg
+ end subroutine sub_m1_a
+
+ integer function sub_m1_b()
+ print*, "sub_m1_b"
+ sub_m1_b = 3
+ end function sub_m1_b
end module mod1
module mod2
integer :: mod2_var_1 = 123
+ real, parameter :: mod2_var_2 = 0.5
+contains
+ subroutine sub_m2_a(a, b)
+ integer :: a
+ logical :: b
+ print*, "sub_m2_a = ", abc
+ print*, "a = ", a
+ print*, "b = ", b
+ end subroutine sub_m2_a
+
+ logical function sub_m2_b(x)
+ real :: x
+ print*, "sub_m2_b = ", cde
+ print*, "x = ", x
+ sub_m2_b = .true.
+ end function sub_m2_b
end module mod2
program info_types_test