Add [-q] [-t TYPEREGEXP] [NAMEREGEXP] args to info [args|functions|locals|variables]
Main changes are:
* stack.c: Add two regexp preg and treg to print_variable_and_value_data
and used them inside do_print_variable_and_value to filter the
variables to print.
* symtab.h: Add a new function bool treg_matches_sym_type_name, that
factorises type matching logic.
* symtab.c: Add type/name matching logic to 'info functions|variables'.
* stack.c : Add type/name matching logic to 'info args|locals'.
gdb/ChangeLog
2018-10-27 Philippe Waroquiers <philippe.waroquiers@skynet.be>
* stack.c (print_variable_and_value_data): Add preg and treg.
(print_frame_local_vars): Add quiet, regexp and t_regexp arguments,
and update callers.
(print_frame_arg_vars): Likewise.
(prepare_reg): New function.
(info_locals_command): Extract info print args and use them.
(info_args_command): Likewise.
(_initialize_stack): Modify on-line help.
* symtab.c (treg_matches_sym_type_name): New function.
(search_symbols): New arg t_regexp.
(symtab_symbol_info): New args quiet, regexp, t_regexp.
(info_variables_command): Extract info print args and use them.
(info_functions_command): Likewise.
(info_types_command): Update call to symtab_symbol_info.
(_initialize_symtab): Modify on-line help.
* symtab.h (treg_matches_sym_type_name): New function.
(search_symbols): New t_regexp arg.
+2018-10-27 Philippe Waroquiers <philippe.waroquiers@skynet.be>
+
+ * stack.c (print_variable_and_value_data): Add preg and treg.
+ (print_frame_local_vars): Add quiet, regexp and t_regexp arguments,
+ and update callers.
+ (print_frame_arg_vars): Likewise.
+ (prepare_reg): New function.
+ (info_locals_command): Extract info print args and use them.
+ (info_args_command): Likewise.
+ (_initialize_stack): Modify on-line help.
+ * symtab.c (treg_matches_sym_type_name): New function.
+ (search_symbols): New arg t_regexp.
+ (symtab_symbol_info): New args quiet, regexp, t_regexp.
+ (info_variables_command): Extract info print args and use them.
+ (info_functions_command): Likewise.
+ (info_types_command): Update call to symtab_symbol_info.
+ (_initialize_symtab): Modify on-line help.
+ * symtab.h (treg_matches_sym_type_name): New function.
+ (search_symbols): New t_regexp arg.
+
2018-10-27 Philippe Waroquiers <philippe.waroquiers@skynet.be>
* cli-utils.c (extract_arg_maybe_quoted): New function.
{
const char **files = symtab_paths.vec.data ();
- symbols = search_symbols (regex, FUNCTIONS_DOMAIN,
+ symbols = search_symbols (regex, FUNCTIONS_DOMAIN, NULL,
symtab_paths.vec.size (), files);
}
else
- symbols = search_symbols (regex, FUNCTIONS_DOMAIN, 0, NULL);
+ symbols = search_symbols (regex, FUNCTIONS_DOMAIN, NULL, 0, NULL);
/* Count the number of symbols (both symbols and optionally minimal
symbols) so we can correctly check the throttle limit. */
/* Prototypes for local functions. */
-static void print_frame_local_vars (struct frame_info *, int,
- struct ui_file *);
+static void print_frame_local_vars (struct frame_info *frame,
+ bool quiet,
+ const char *regexp, const char *t_regexp,
+ int num_tabs, struct ui_file *stream);
static void print_frame (struct frame_info *frame, int print_level,
enum print_what print_what, int print_args,
{
struct frame_id frame_id = get_frame_id (fi);
- print_frame_local_vars (fi, 1, gdb_stdout);
+ print_frame_local_vars (fi, false, NULL, NULL, 1, gdb_stdout);
/* print_frame_local_vars invalidates FI. */
fi = frame_find_by_id (frame_id);
struct print_variable_and_value_data
{
+ gdb::optional<compiled_regex> preg;
+ gdb::optional<compiled_regex> treg;
struct frame_id frame_id;
int num_tabs;
struct ui_file *stream;
= (struct print_variable_and_value_data *) cb_data;
struct frame_info *frame;
+ if (p->preg.has_value ()
+ && p->preg->exec (SYMBOL_NATURAL_NAME (sym), 0,
+ NULL, 0) != 0)
+ return;
+ if (p->treg.has_value ()
+ && !treg_matches_sym_type_name (*p->treg, sym))
+ return;
+
frame = frame_find_by_id (p->frame_id);
if (frame == NULL)
{
p->values_printed = 1;
}
+/* Prepares the regular expression REG from REGEXP.
+ If REGEXP is NULL, it results in an empty regular expression. */
+
+static void
+prepare_reg (const char *regexp, gdb::optional<compiled_regex> *reg)
+{
+ if (regexp != NULL)
+ {
+ int cflags = REG_NOSUB | (case_sensitivity == case_sensitive_off
+ ? REG_ICASE : 0);
+ reg->emplace (regexp, cflags, _("Invalid regexp"));
+ }
+ else
+ reg->reset ();
+}
+
/* Print all variables from the innermost up to the function block of FRAME.
Print them with values to STREAM indented by NUM_TABS.
+ If REGEXP is not NULL, only print local variables whose name
+ matches REGEXP.
+ If T_REGEXP is not NULL, only print local variables whose type
+ matches T_REGEXP.
+ If no local variables have been printed and !QUIET, prints a message
+ explaining why no local variables could be printed.
This function will invalidate FRAME. */
static void
-print_frame_local_vars (struct frame_info *frame, int num_tabs,
- struct ui_file *stream)
+print_frame_local_vars (struct frame_info *frame,
+ bool quiet,
+ const char *regexp, const char *t_regexp,
+ int num_tabs, struct ui_file *stream)
{
struct print_variable_and_value_data cb_data;
const struct block *block;
if (!get_frame_pc_if_available (frame, &pc))
{
- fprintf_filtered (stream,
- _("PC unavailable, cannot determine locals.\n"));
+ if (!quiet)
+ fprintf_filtered (stream,
+ _("PC unavailable, cannot determine locals.\n"));
return;
}
block = get_frame_block (frame, 0);
if (block == 0)
{
- fprintf_filtered (stream, "No symbol table info available.\n");
+ if (!quiet)
+ fprintf_filtered (stream, "No symbol table info available.\n");
return;
}
+ prepare_reg (regexp, &cb_data.preg);
+ prepare_reg (t_regexp, &cb_data.treg);
cb_data.frame_id = get_frame_id (frame);
cb_data.num_tabs = 4 * num_tabs;
cb_data.stream = stream;
do_print_variable_and_value,
&cb_data);
- if (!cb_data.values_printed)
- fprintf_filtered (stream, _("No locals.\n"));
+ if (!cb_data.values_printed && !quiet)
+ {
+ if (regexp == NULL && t_regexp == NULL)
+ fprintf_filtered (stream, _("No locals.\n"));
+ else
+ fprintf_filtered (stream, _("No matching locals.\n"));
+ }
}
void
info_locals_command (const char *args, int from_tty)
{
+ std::string regexp;
+ std::string t_regexp;
+ bool quiet = false;
+
+ while (args != NULL
+ && extract_info_print_args (&args, &quiet, ®exp, &t_regexp))
+ ;
+
+ if (args != NULL)
+ report_unrecognized_option_error ("info locals", args);
+
print_frame_local_vars (get_selected_frame (_("No frame selected.")),
+ quiet,
+ regexp.empty () ? NULL : regexp.c_str (),
+ t_regexp.empty () ? NULL : t_regexp.c_str (),
0, gdb_stdout);
}
/* Print all argument variables of the function of FRAME.
Print them with values to STREAM.
+ If REGEXP is not NULL, only print argument variables whose name
+ matches REGEXP.
+ If T_REGEXP is not NULL, only print argument variables whose type
+ matches T_REGEXP.
+ If no argument variables have been printed and !QUIET, prints a message
+ explaining why no argument variables could be printed.
This function will invalidate FRAME. */
static void
-print_frame_arg_vars (struct frame_info *frame, struct ui_file *stream)
+print_frame_arg_vars (struct frame_info *frame,
+ bool quiet,
+ const char *regexp, const char *t_regexp,
+ struct ui_file *stream)
{
struct print_variable_and_value_data cb_data;
struct symbol *func;
CORE_ADDR pc;
+ gdb::optional<compiled_regex> preg;
+ gdb::optional<compiled_regex> treg;
if (!get_frame_pc_if_available (frame, &pc))
{
- fprintf_filtered (stream, _("PC unavailable, cannot determine args.\n"));
+ if (!quiet)
+ fprintf_filtered (stream,
+ _("PC unavailable, cannot determine args.\n"));
return;
}
func = get_frame_function (frame);
if (func == NULL)
{
- fprintf_filtered (stream, _("No symbol table info available.\n"));
+ if (!quiet)
+ fprintf_filtered (stream, _("No symbol table info available.\n"));
return;
}
+ prepare_reg (regexp, &cb_data.preg);
+ prepare_reg (t_regexp, &cb_data.treg);
cb_data.frame_id = get_frame_id (frame);
cb_data.num_tabs = 0;
cb_data.stream = stream;
/* do_print_variable_and_value invalidates FRAME. */
frame = NULL;
- if (!cb_data.values_printed)
- fprintf_filtered (stream, _("No arguments.\n"));
+ if (!cb_data.values_printed && !quiet)
+ {
+ if (regexp == NULL && t_regexp == NULL)
+ fprintf_filtered (stream, _("No arguments.\n"));
+ else
+ fprintf_filtered (stream, _("No matching arguments.\n"));
+ }
}
void
-info_args_command (const char *ignore, int from_tty)
+info_args_command (const char *args, int from_tty)
{
+ std::string regexp;
+ std::string t_regexp;
+ bool quiet;
+
+ while (args != NULL
+ && extract_info_print_args (&args, &quiet, ®exp, &t_regexp))
+ ;
+
+ if (args != NULL)
+ report_unrecognized_option_error ("info args", args);
+
+
print_frame_arg_vars (get_selected_frame (_("No frame selected.")),
+ quiet,
+ regexp.empty () ? NULL : regexp.c_str (),
+ t_regexp.empty () ? NULL : t_regexp.c_str (),
gdb_stdout);
}
\f
&info_frame_cmd_list);
add_info ("locals", info_locals_command,
- _("Local variables of current stack frame."));
+ info_print_args_help (_("\
+All local variables of current stack frame or those matching REGEXPs.\n\
+Usage: info locals [-q] [-t TYPEREGEXP] [NAMEREGEXP]\n\
+Prints the local variables of the current stack frame.\n"),
+ _("local variables")));
add_info ("args", info_args_command,
- _("Argument variables of current stack frame."));
+ info_print_args_help (_("\
+All argument variables of current stack frame or those matching REGEXPs.\n\
+Usage: info args [-q] [-t TYPEREGEXP] [NAMEREGEXP]\n\
+Prints the argument variables of the current stack frame.\n"),
+ _("argument variables")));
if (dbx_commands)
add_com ("func", class_stack, func_command, _("\
#include "cli/cli-utils.h"
#include "fnmatch.h"
#include "hashtab.h"
+#include "typeprint.h"
#include "gdb_obstack.h"
#include "block.h"
SYMBOL_PRINT_NAME (sym_b.symbol));
}
+/* Returns true if the type_name of symbol_type of SYM matches TREG.
+ If SYM has no symbol_type or symbol_name, returns false. */
+
+bool
+treg_matches_sym_type_name (const compiled_regex &treg,
+ const struct symbol *sym)
+{
+ struct type *sym_type;
+ std::string printed_sym_type_name;
+
+ if (symbol_lookup_debug > 1)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "treg_matches_sym_type_name\n sym %s\n",
+ SYMBOL_NATURAL_NAME (sym));
+ }
+
+ sym_type = SYMBOL_TYPE (sym);
+ if (sym_type == NULL)
+ return false;
+
+ if (language_mode == language_mode_auto)
+ {
+ scoped_restore_current_language l;
+
+ set_language (SYMBOL_LANGUAGE (sym));
+ printed_sym_type_name = type_to_string (sym_type);
+ }
+ else
+ printed_sym_type_name = type_to_string (sym_type);
+
+ if (symbol_lookup_debug > 1)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ " sym_type_name %s\n",
+ printed_sym_type_name.c_str ());
+ }
+
+
+ if (printed_sym_type_name.empty ())
+ return false;
+
+ return treg.exec (printed_sym_type_name.c_str (), 0, NULL, 0) == 0;
+}
+
+
/* Sort the symbols in RESULT and remove duplicates. */
static void
Only symbols of KIND are searched:
VARIABLES_DOMAIN - search all symbols, excluding functions, type names,
- and constants (enums)
+ 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
std::vector<symbol_search>
search_symbols (const char *regexp, enum search_domain kind,
+ const char *t_regexp,
int nfiles, const char *files[])
{
struct compunit_symtab *cust;
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);
preg.emplace (regexp, cflags, _("Invalid regexp"));
}
+ if (t_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. */
lookup_name_info::match_any (),
[&] (const char *symname)
{
- return (!preg || preg->exec (symname,
- 0, NULL, 0) == 0);
+ return (!preg.has_value ()
+ || preg->exec (symname,
+ 0, NULL, 0) == 0);
},
NULL,
kind);
|| MSYMBOL_TYPE (msymbol) == ourtype3
|| MSYMBOL_TYPE (msymbol) == ourtype4)
{
- if (!preg
+ if (!preg.has_value ()
|| preg->exec (MSYMBOL_NATURAL_NAME (msymbol), 0,
NULL, 0) == 0)
{
files, nfiles, 1))
&& file_matches (symtab_to_fullname (real_symtab),
files, nfiles, 0)))
- && ((!preg
+ && ((!preg.has_value ()
|| preg->exec (SYMBOL_NATURAL_NAME (sym), 0,
NULL, 0) == 0)
&& ((kind == VARIABLES_DOMAIN
We only want to skip enums here. */
&& !(SYMBOL_CLASS (sym) == LOC_CONST
&& (TYPE_CODE (SYMBOL_TYPE (sym))
- == TYPE_CODE_ENUM)))
- || (kind == FUNCTIONS_DOMAIN
- && SYMBOL_CLASS (sym) == LOC_BLOCK)
+ == 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))))
{
|| MSYMBOL_TYPE (msymbol) == ourtype3
|| MSYMBOL_TYPE (msymbol) == ourtype4)
{
- if (!preg || preg->exec (MSYMBOL_NATURAL_NAME (msymbol), 0,
- NULL, 0) == 0)
+ /* If the user wants to see var matching a type regexp,
+ then never give a minimal symbol. */
+ if (kind != VARIABLES_DOMAIN
+ && !treg.has_value () /* minimal symbol has never a type ???? */
+ && (!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. */
matches. */
static void
-symtab_symbol_info (const char *regexp, enum search_domain kind, int from_tty)
+symtab_symbol_info (bool quiet,
+ const char *regexp, enum search_domain kind,
+ const char *t_regexp, int from_tty)
{
static const char * const classnames[] =
{"variable", "function", "type"};
gdb_assert (kind <= TYPES_DOMAIN);
/* Must make sure that if we're interrupted, symbols gets freed. */
- std::vector<symbol_search> symbols = search_symbols (regexp, kind, 0, NULL);
+ std::vector<symbol_search> symbols = search_symbols (regexp, kind,
+ t_regexp, 0, NULL);
- if (regexp != NULL)
- printf_filtered (_("All %ss matching regular expression \"%s\":\n"),
- classnames[kind], regexp);
- else
- printf_filtered (_("All defined %ss:\n"), classnames[kind]);
+ if (!quiet)
+ {
+ if (regexp != NULL)
+ {
+ if (t_regexp != NULL)
+ printf_filtered
+ (_("All %ss matching regular expression \"%s\""
+ " with type matching regulation expression \"%s\":\n"),
+ classnames[kind], regexp, t_regexp);
+ else
+ printf_filtered (_("All %ss matching regular expression \"%s\":\n"),
+ classnames[kind], regexp);
+ }
+ else
+ {
+ if (t_regexp != NULL)
+ printf_filtered
+ (_("All defined %ss"
+ " with type matching regulation expression \"%s\" :\n"),
+ classnames[kind], t_regexp);
+ else
+ printf_filtered (_("All defined %ss:\n"), classnames[kind]);
+ }
+ }
for (const symbol_search &p : symbols)
{
{
if (first)
{
- printf_filtered (_("\nNon-debugging symbols:\n"));
+ if (!quiet)
+ printf_filtered (_("\nNon-debugging symbols:\n"));
first = 0;
}
print_msymbol_info (p.msymbol);
}
static void
-info_variables_command (const char *regexp, int from_tty)
+info_variables_command (const char *args, int from_tty)
{
- symtab_symbol_info (regexp, VARIABLES_DOMAIN, from_tty);
+ std::string regexp;
+ std::string t_regexp;
+ bool quiet = false;
+
+ while (args != NULL
+ && extract_info_print_args (&args, &quiet, ®exp, &t_regexp))
+ ;
+
+ if (args != NULL)
+ report_unrecognized_option_error ("info variables", args);
+
+ symtab_symbol_info (quiet,
+ regexp.empty () ? NULL : regexp.c_str (),
+ VARIABLES_DOMAIN,
+ t_regexp.empty () ? NULL : t_regexp.c_str (),
+ from_tty);
}
+
static void
-info_functions_command (const char *regexp, int from_tty)
+info_functions_command (const char *args, int from_tty)
{
- symtab_symbol_info (regexp, FUNCTIONS_DOMAIN, from_tty);
+ std::string regexp;
+ std::string t_regexp;
+ bool quiet;
+
+ while (args != NULL
+ && extract_info_print_args (&args, &quiet, ®exp, &t_regexp))
+ ;
+
+ if (args != NULL)
+ report_unrecognized_option_error ("info functions", args);
+
+ symtab_symbol_info (quiet,
+ regexp.empty () ? NULL : regexp.c_str (),
+ FUNCTIONS_DOMAIN,
+ t_regexp.empty () ? NULL : t_regexp.c_str (),
+ from_tty);
}
static void
info_types_command (const char *regexp, int from_tty)
{
- symtab_symbol_info (regexp, TYPES_DOMAIN, from_tty);
+ symtab_symbol_info (false, regexp, TYPES_DOMAIN, NULL, from_tty);
}
/* Breakpoint all functions matching regular expression. */
std::vector<symbol_search> symbols = search_symbols (regexp,
FUNCTIONS_DOMAIN,
+ NULL,
nfiles, files);
scoped_rbreak_breakpoints finalize;
symbol_cache_key
= register_program_space_data_with_cleanup (NULL, symbol_cache_cleanup);
- add_info ("variables", info_variables_command, _("\
-All global and static variable names, or those matching REGEXP."));
+ add_info ("variables", info_variables_command,
+ info_print_args_help (_("\
+All global and static variable names or those matching REGEXPs.\n\
+Usage: info variables [-q] [-t TYPEREGEXP] [NAMEREGEXP]\n\
+Prints the global and static variables.\n"),
+ _("global and static variables")));
if (dbx_commands)
- add_com ("whereis", class_info, info_variables_command, _("\
-All global and static variable names, or those matching REGEXP."));
+ add_com ("whereis", class_info, info_variables_command,
+ info_print_args_help (_("\
+All global and static variable names, or those matching REGEXPs.\n\
+Usage: whereis [-q] [-t TYPEREGEXP] [NAMEREGEXP]\n\
+Prints the global and static variables.\n"),
+ _("global and static variables")));
add_info ("functions", info_functions_command,
- _("All function names, or those matching REGEXP."));
+ info_print_args_help (_("\
+All function names or those matching REGEXPs.\n\
+Usage: info functions [-q] [-t TYPEREGEXP] [NAMEREGEXP]\n\
+Prints the functions.\n"),
+ _("functions")));
/* FIXME: This command has at least the following problems:
1. It prints builtin types (in a very strange and confusing fashion).
#include <string>
#include "gdb_vecs.h"
#include "gdbtypes.h"
+#include "gdb_regex.h"
#include "common/enum-flags.h"
#include "common/function-view.h"
#include "common/gdb_optional.h"
};
extern std::vector<symbol_search> search_symbols (const char *,
- enum search_domain, int,
+ enum search_domain,
+ const char *,
+ int,
const char **);
+extern bool treg_matches_sym_type_name (const compiled_regex &treg,
+ const struct symbol *sym);
/* The name of the ``main'' function.
FIXME: cagney/2001-03-20: Can't make main_name() const since some