From 12615cba8411c845b33b98cc616439c66a34f03a Mon Sep 17 00:00:00 2001 From: Philippe Waroquiers Date: Sun, 1 Jul 2018 22:56:56 +0200 Subject: [PATCH] Add [-q] [-t TYPEREGEXP] [NAMEREGEXP] args to info [args|functions|locals|variables] 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 * 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. --- gdb/ChangeLog | 20 +++++ gdb/python/python.c | 4 +- gdb/stack.c | 139 +++++++++++++++++++++++++++----- gdb/symtab.c | 191 +++++++++++++++++++++++++++++++++++++------- gdb/symtab.h | 7 +- 5 files changed, 312 insertions(+), 49 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index ea033a798f9..d105e74dc51 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,23 @@ +2018-10-27 Philippe Waroquiers + + * 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 * cli-utils.c (extract_arg_maybe_quoted): New function. diff --git a/gdb/python/python.c b/gdb/python/python.c index 8fbce784695..348405e2059 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -743,11 +743,11 @@ gdbpy_rbreak (PyObject *self, PyObject *args, PyObject *kw) { 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. */ diff --git a/gdb/stack.c b/gdb/stack.c index 87b493f7901..abbaf5d4a7a 100644 --- a/gdb/stack.c +++ b/gdb/stack.c @@ -88,8 +88,10 @@ const char *print_entry_values = print_entry_values_default; /* 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, @@ -1878,7 +1880,7 @@ backtrace_command_1 (const char *count_exp, frame_filter_flags flags, { 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); @@ -2060,6 +2062,8 @@ iterate_over_block_local_vars (const struct block *block, struct print_variable_and_value_data { + gdb::optional preg; + gdb::optional treg; struct frame_id frame_id; int num_tabs; struct ui_file *stream; @@ -2077,6 +2081,14 @@ do_print_variable_and_value (const char *print_name, = (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) { @@ -2092,14 +2104,38 @@ do_print_variable_and_value (const char *print_name, 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 *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; @@ -2107,18 +2143,22 @@ print_frame_local_vars (struct frame_info *frame, int num_tabs, 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; @@ -2134,14 +2174,33 @@ print_frame_local_vars (struct frame_info *frame, int num_tabs, 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); } @@ -2180,29 +2239,45 @@ iterate_over_block_arg_vars (const struct block *b, /* 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 preg; + gdb::optional 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; @@ -2214,14 +2289,34 @@ print_frame_arg_vars (struct frame_info *frame, struct ui_file *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); } @@ -2994,9 +3089,17 @@ Usage: info frame level LEVEL"), &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, _("\ diff --git a/gdb/symtab.c b/gdb/symtab.c index 2e48d6527e8..cd27a75e8ca 100644 --- a/gdb/symtab.c +++ b/gdb/symtab.c @@ -43,6 +43,7 @@ #include "cli/cli-utils.h" #include "fnmatch.h" #include "hashtab.h" +#include "typeprint.h" #include "gdb_obstack.h" #include "block.h" @@ -4266,6 +4267,52 @@ symbol_search::compare_search_syms (const symbol_search &sym_a, 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 @@ -4281,7 +4328,9 @@ sort_search_symbols_remove_dups (std::vector *result) 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 @@ -4292,6 +4341,7 @@ sort_search_symbols_remove_dups (std::vector *result) std::vector search_symbols (const char *regexp, enum search_domain kind, + const char *t_regexp, int nfiles, const char *files[]) { struct compunit_symtab *cust; @@ -4317,6 +4367,7 @@ search_symbols (const char *regexp, enum search_domain kind, enum minimal_symbol_type ourtype4; std::vector result; gdb::optional preg; + gdb::optional treg; gdb_assert (kind <= TYPES_DOMAIN); @@ -4366,6 +4417,13 @@ search_symbols (const char *regexp, enum search_domain kind, 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. */ @@ -4377,8 +4435,9 @@ search_symbols (const char *regexp, enum search_domain kind, 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); @@ -4413,7 +4472,7 @@ search_symbols (const char *regexp, enum search_domain 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) { @@ -4452,7 +4511,7 @@ search_symbols (const char *regexp, enum search_domain kind, 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 @@ -4464,9 +4523,13 @@ search_symbols (const char *regexp, enum search_domain kind, 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)))) { @@ -4497,8 +4560,13 @@ search_symbols (const char *regexp, enum search_domain kind, || 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. */ @@ -4599,7 +4667,9 @@ print_msymbol_info (struct bound_minimal_symbol msymbol) 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"}; @@ -4609,13 +4679,33 @@ symtab_symbol_info (const char *regexp, enum search_domain kind, int from_tty) gdb_assert (kind <= TYPES_DOMAIN); /* Must make sure that if we're interrupted, symbols gets freed. */ - std::vector symbols = search_symbols (regexp, kind, 0, NULL); + std::vector 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) { @@ -4625,7 +4715,8 @@ symtab_symbol_info (const char *regexp, enum search_domain kind, int from_tty) { if (first) { - printf_filtered (_("\nNon-debugging symbols:\n")); + if (!quiet) + printf_filtered (_("\nNon-debugging symbols:\n")); first = 0; } print_msymbol_info (p.msymbol); @@ -4643,22 +4734,53 @@ symtab_symbol_info (const char *regexp, enum search_domain kind, int from_tty) } 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. */ @@ -4701,6 +4823,7 @@ rbreak_command (const char *regexp, int from_tty) std::vector symbols = search_symbols (regexp, FUNCTIONS_DOMAIN, + NULL, nfiles, files); scoped_rbreak_breakpoints finalize; @@ -5902,14 +6025,26 @@ _initialize_symtab (void) 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). diff --git a/gdb/symtab.h b/gdb/symtab.h index b91ec12b290..e0b870135b6 100644 --- a/gdb/symtab.h +++ b/gdb/symtab.h @@ -25,6 +25,7 @@ #include #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" @@ -2057,8 +2058,12 @@ private: }; extern std::vector 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 -- 2.30.2