[RFAv2,3/6] Add [-q] [-t TYPEREGEXP] [NAMEREGEXP] args to info [args|functions|locals|variables]

Message ID 20180826165359.1600-4-philippe.waroquiers@skynet.be
State New, archived
Headers

Commit Message

Philippe Waroquiers Aug. 26, 2018, 4:53 p.m. UTC
  Add [-q] [-t TYPEREGEXP] [NAMEREGEXP] args to info [args|functions|locals|variables]

Main changes are:
* stack.h: Add two regexp args to iterate_over_block_arg_vars
  and iterate_over_block_local_vars, and update all impacted files/callers.
  As stack.h now uses a type defined in gdb_regex.h, all files including stack.h
  need to include gdb_regex.h.

* 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-08-26  Philippe Waroquiers  <philippe.waroquiers@skynet.be>

	* linespec.c: Include gdb_exex.h.
	* mi/mi-cmd-stack.c: Likewise.
	* python/py-frame.c: Likewise.
	* python/python.c: Likewise.
	* skip.c: Likewise.
	* symfile.c: Likewise.
	* tracepoint.c: Likewise.
	* stack.h (iterate_over_block_arg_vars): Add preg and treg arguments.
	(iterate_over_block_local_vars): Likewise.
	* stack.c (iterate_over_block_arg_vars): Add preg and treg arguments,
	and update callers.
	(iterate_over_block_local_vars): Likewise.
	(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/linespec.c        |   1 +
 gdb/mi/mi-cmd-stack.c |   1 +
 gdb/python/py-frame.c |   1 +
 gdb/python/python.c   |   4 +-
 gdb/skip.c            |   1 +
 gdb/stack.c           | 162 ++++++++++++++++++++++++++++++++++-------
 gdb/stack.h           |   4 ++
 gdb/symfile.c         |   1 +
 gdb/symtab.c          | 164 +++++++++++++++++++++++++++++++++++-------
 gdb/symtab.h          |   8 ++-
 gdb/tracepoint.c      |   8 ++-
 11 files changed, 299 insertions(+), 56 deletions(-)
  

Comments

Tom Tromey Sept. 18, 2018, 3:51 p.m. UTC | #1
>>>>> "Philippe" == Philippe Waroquiers <philippe.waroquiers@skynet.be> writes:

Philippe>   As stack.h now uses a type defined in gdb_regex.h, all files including stack.h
Philippe>   need to include gdb_regex.h.

It's better to just include gdb_regex.h from stack.h in this situation.

Philippe> +	  if (preg

I think preg.has_value ().  gdb is trending away from these bool
conversions, I think.  At least that's been the style for pointers.

Philippe> +	  if (treg

Here too.

Philippe> +/* Prepares the regular expression REG from REGEXP.
Philippe> +   If REGEXP is NULL, it results in an empty regular expression.  */
Philippe> +static void
Philippe> +prepare_reg (const char *regexp, gdb::optional<compiled_regex> &reg)

Out parameters should be pointers in the gdb style.

Philippe> -  iterate_over_block_local_vars (block,
Philippe> +  iterate_over_block_local_vars (block, preg, treg,
Philippe>  				 do_print_variable_and_value,
Philippe>  				 &cb_data);

iterate_over_block_local_vars already takes some opaque data that it
just passes through to the callback.  So, I think there should not be
a need to add the regexp parameters directly to it.  Instead they can be
put into the cb_data here.

Philippe>  void
Philippe>  iterate_over_block_arg_vars (const struct block *b,
Philippe> +			     const gdb::optional<compiled_regex> &preg,
Philippe> +			     const gdb::optional<compiled_regex> &treg,
Philippe>  			     iterate_over_block_arg_local_vars_cb cb,
Philippe>  			     void *cb_data)

Same here.

Philippe> +/* Returns true if the type_name of symbol_type of SYM matches TREG.
Philippe> +   If SYM has no symbol_type or symbol_name, returns false.  */
Philippe> +
Philippe> +bool
Philippe> +treg_matches_sym_type_name (const compiled_regex &treg,
Philippe> +			    const struct symbol *sym)
Philippe> +{
Philippe> +  if (language_mode == language_mode_auto)
Philippe> +    language_def (SYMBOL_LANGUAGE (sym))->la_print_type
Philippe> +      (sym_type, "", &printed_sym_type_name,
Philippe> +       -1, 0, &default_ptype_flags);

I think this won't actually work, because the type printing code is free
to use current_language.  This is not good, but it is how it is.

So instead I think what this should do is save and restore the current
language.  IIRC there's a helper RAII class for that already.

Then you can just call type_print and drop patch #2.

Philippe> +extern bool
Philippe> +treg_matches_sym_type_name (const compiled_regex &treg,
Philippe> +			    const struct symbol *sym);
 
No newline after the "bool" for a declaration.

Tom
  
Philippe Waroquiers Sept. 23, 2018, 9:34 p.m. UTC | #2
Feedback below ...

RFAv3 will follow soon

Thanks for the comments.

Philippe


On Tue, 2018-09-18 at 09:51 -0600, Tom Tromey wrote:
> > > > > > "Philippe" == Philippe Waroquiers <philippe.waroquiers@skynet.be> writes:
> 
> Philippe>   As stack.h now uses a type defined in gdb_regex.h, all files including stack.h
> Philippe>   need to include gdb_regex.h.
> 
> It's better to just include gdb_regex.h from stack.h in this situation.
Done (rather, no need anymore for regexp in stack.h).

> 
> Philippe> +	  if (preg
> 
> I think preg.has_value ().  gdb is trending away from these bool
> conversions, I think.  At least that's been the style for pointers.
> 
> Philippe> +	  if (treg
> 
> Here too.
Done.

> 
> Philippe> +/* Prepares the regular expression REG from REGEXP.
> Philippe> +   If REGEXP is NULL, it results in an empty regular expression.  */
> Philippe> +static void
> Philippe> +prepare_reg (const char *regexp, gdb::optional<compiled_regex> &reg)
> 
> Out parameters should be pointers in the gdb style.
Done.


> 
> Philippe> -  iterate_over_block_local_vars (block,
> Philippe> +  iterate_over_block_local_vars (block, preg, treg,
> Philippe>  				 do_print_variable_and_value,
> Philippe>  				 &cb_data);
> 
> iterate_over_block_local_vars already takes some opaque data that it
> just passes through to the callback.  So, I think there should not be
> a need to add the regexp parameters directly to it.  Instead they can be
> put into the cb_data here.
> 
> Philippe>  void
> Philippe>  iterate_over_block_arg_vars (const struct block *b,
> Philippe> +			     const gdb::optional<compiled_regex> &preg,
> Philippe> +			     const gdb::optional<compiled_regex> &treg,
> Philippe>  			     iterate_over_block_arg_local_vars_cb cb,
> Philippe>  			     void *cb_data)
> 
> Same here.

Done: the preg/treg regexp have been put in the opaque cb_data,
and regexp filtering logic has been moved to do_print_variable_and_value.


> 
> Philippe> +/* Returns true if the type_name of symbol_type of SYM matches TREG.
> Philippe> +   If SYM has no symbol_type or symbol_name, returns false.  */
> Philippe> +
> Philippe> +bool
> Philippe> +treg_matches_sym_type_name (const compiled_regex &treg,
> Philippe> +			    const struct symbol *sym)
> Philippe> +{
> Philippe> +  if (language_mode == language_mode_auto)
> Philippe> +    language_def (SYMBOL_LANGUAGE (sym))->la_print_type
> Philippe> +      (sym_type, "", &printed_sym_type_name,
> Philippe> +       -1, 0, &default_ptype_flags);
> 
> I think this won't actually work, because the type printing code is free
> to use current_language.  This is not good, but it is how it is.
> 
> So instead I think what this should do is save and restore the current
> language.  IIRC there's a helper RAII class for that already.
> 
> Then you can just call type_print and drop patch #2.
Done.

> 
> Philippe> +extern bool
> Philippe> +treg_matches_sym_type_name (const compiled_regex &treg,
> Philippe> +			    const struct symbol *sym);
>  
> No newline after the "bool" for a declaration.
Done.

Thanks
Philippe
  

Patch

diff --git a/gdb/linespec.c b/gdb/linespec.c
index 73fbe4af3b..ba23eeaba6 100644
--- a/gdb/linespec.c
+++ b/gdb/linespec.c
@@ -42,6 +42,7 @@ 
 #include "cli/cli-utils.h"
 #include "filenames.h"
 #include "ada-lang.h"
+#include "gdb_regex.h"
 #include "stack.h"
 #include "location.h"
 #include "common/function-view.h"
diff --git a/gdb/mi/mi-cmd-stack.c b/gdb/mi/mi-cmd-stack.c
index 52660bdd49..f109353a34 100644
--- a/gdb/mi/mi-cmd-stack.c
+++ b/gdb/mi/mi-cmd-stack.c
@@ -25,6 +25,7 @@ 
 #include "ui-out.h"
 #include "symtab.h"
 #include "block.h"
+#include "gdb_regex.h"
 #include "stack.h"
 #include "dictionary.h"
 #include "language.h"
diff --git a/gdb/python/py-frame.c b/gdb/python/py-frame.c
index ec456e9e77..b566149f76 100644
--- a/gdb/python/py-frame.c
+++ b/gdb/python/py-frame.c
@@ -22,6 +22,7 @@ 
 #include "block.h"
 #include "frame.h"
 #include "symtab.h"
+#include "gdb_regex.h"
 #include "stack.h"
 #include "value.h"
 #include "python-internal.h"
diff --git a/gdb/python/python.c b/gdb/python/python.c
index 20fc674f20..b80c874c47 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -766,11 +766,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/skip.c b/gdb/skip.c
index 7a6f2e712b..b7f7b10167 100644
--- a/gdb/skip.c
+++ b/gdb/skip.c
@@ -24,6 +24,7 @@ 
 #include "gdbcmd.h"
 #include "command.h"
 #include "completer.h"
+#include "gdb_regex.h"
 #include "stack.h"
 #include "cli/cli-utils.h"
 #include "arch-utils.h"
diff --git a/gdb/stack.c b/gdb/stack.c
index 40ff99b8fa..f3e8af6031 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -25,6 +25,7 @@ 
 #include "language.h"
 #include "frame.h"
 #include "gdbcmd.h"
+#include "gdb_regex.h"
 #include "gdbcore.h"
 #include "target.h"
 #include "source.h"
@@ -89,8 +90,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,
@@ -1829,7 +1832,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);
@@ -1903,10 +1906,14 @@  backtrace_command (const char *arg, int from_tty)
 }
 
 /* Iterate over the local variables of a block B, calling CB with
-   CB_DATA.  */
+   CB_DATA.
+   Only local variables with name/type matching PREG/TREG are iterated
+   on.  */
 
 static void
 iterate_over_block_locals (const struct block *b,
+			   const gdb::optional<compiled_regex> &preg,
+			   const gdb::optional<compiled_regex> &treg,
 			   iterate_over_block_arg_local_vars_cb cb,
 			   void *cb_data)
 {
@@ -1926,6 +1933,13 @@  iterate_over_block_locals (const struct block *b,
 	    break;
 	  if (SYMBOL_DOMAIN (sym) == COMMON_BLOCK_DOMAIN)
 	    break;
+	  if (preg
+	      && preg->exec (SYMBOL_NATURAL_NAME (sym), 0,
+			     NULL, 0) != 0)
+	    break;
+	  if (treg
+	      && !treg_matches_sym_type_name (*treg, sym))
+	    break;
 	  (*cb) (SYMBOL_PRINT_NAME (sym), sym, cb_data);
 	  break;
 
@@ -1987,16 +2001,20 @@  print_block_frame_labels (struct gdbarch *gdbarch, struct block *b,
 #endif
 
 /* Iterate over all the local variables in block B, including all its
-   superblocks, stopping when the top-level block is reached.  */
+   superblocks, stopping when the top-level block is reached.
+   Only local variables with name/type matching PREG/TREG are iterated
+   on.  */
 
 void
 iterate_over_block_local_vars (const struct block *block,
+			       const gdb::optional<compiled_regex> &preg,
+			       const gdb::optional<compiled_regex> &treg,
 			       iterate_over_block_arg_local_vars_cb cb,
 			       void *cb_data)
 {
   while (block)
     {
-      iterate_over_block_locals (block, cb, cb_data);
+      iterate_over_block_locals (block, preg, treg, cb, cb_data);
       /* After handling the function's top-level block, stop.  Don't
 	 continue to its superblock, the block of per-file
 	 symbols.  */
@@ -2043,30 +2061,57 @@  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<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;
   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 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;
     }
 
@@ -2075,31 +2120,53 @@  print_frame_local_vars (struct frame_info *frame, int num_tabs,
   cb_data.stream = stream;
   cb_data.values_printed = 0;
 
+  prepare_reg (regexp, preg);
+  prepare_reg (t_regexp, treg);
+
   /* Temporarily change the selected frame to the given FRAME.
      This allows routines that rely on the selected frame instead
      of being given a frame as parameter to use the correct frame.  */
   scoped_restore_selected_frame restore_selected_frame;
   select_frame (frame);
 
-  iterate_over_block_local_vars (block,
+  iterate_over_block_local_vars (block, preg, treg,
 				 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;
+
+  extract_info_print_args ("info locals", &args, &quiet, &regexp, &t_regexp);
   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);
 }
 
-/* Iterate over all the argument variables in block B.  */
+/* Iterate over all the argument variables in block B.
+   If PREG has a value, only prints the argument variables
+   with name matching PREG.
+   If TREG has a value, only prints the argument variables
+   with type matching TREG.  */
 
 void
 iterate_over_block_arg_vars (const struct block *b,
+			     const gdb::optional<compiled_regex> &preg,
+			     const gdb::optional<compiled_regex> &treg,
 			     iterate_over_block_arg_local_vars_cb cb,
 			     void *cb_data)
 {
@@ -2109,7 +2176,12 @@  iterate_over_block_arg_vars (const struct block *b,
   ALL_BLOCK_SYMBOLS (b, iter, sym)
     {
       /* Don't worry about things which aren't arguments.  */
-      if (SYMBOL_IS_ARGUMENT (sym))
+      if (SYMBOL_IS_ARGUMENT (sym)
+	  && (!preg
+	      || preg->exec (SYMBOL_NATURAL_NAME (sym), 0,
+			     NULL, 0) == 0)
+	  && (!treg
+	      || treg_matches_sym_type_name (*treg, sym)))
 	{
 	  /* We have to look up the symbol because arguments can have
 	     two entries (one a parameter, one a local) and the one we
@@ -2121,7 +2193,6 @@  iterate_over_block_arg_vars (const struct block *b,
 	     symbol is double and the type of the LOC_LOCAL symbol is
 	     float).  There are also LOC_ARG/LOC_REGISTER pairs which
 	     are not combined in symbol-reading.  */
-
 	  sym2 = lookup_symbol_search_name (SYMBOL_SEARCH_NAME (sym),
 					    b, VAR_DOMAIN).symbol;
 	  (*cb) (SYMBOL_PRINT_NAME (sym), sym2, cb_data);
@@ -2131,26 +2202,40 @@  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<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;
     }
 
@@ -2159,20 +2244,37 @@  print_frame_arg_vars (struct frame_info *frame, struct ui_file *stream)
   cb_data.stream = stream;
   cb_data.values_printed = 0;
 
+  prepare_reg (regexp, preg);
+  prepare_reg (t_regexp, treg);
+
   iterate_over_block_arg_vars (SYMBOL_BLOCK_VALUE (func),
+			       preg, treg,
 			       do_print_variable_and_value, &cb_data);
 
   /* 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;
+
+  extract_info_print_args ("info args", &args, &quiet, &regexp, &t_regexp);
   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);
 }
 
@@ -2815,10 +2917,16 @@  on this backtrace."));
   add_info ("frame", info_frame_command,
 	    _("All about selected stack frame, or frame at ADDR."));
   add_info_alias ("f", "frame", 1);
-  add_info ("locals", info_locals_command,
-	    _("Local variables of current stack frame."));
-  add_info ("args", info_args_command,
-	    _("Argument variables of current stack frame."));
+  add_info ("locals", info_locals_command, _("\
+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"
+INFO_PRINT_ARGS_HELP ("local variables")));
+  add_info ("args", info_args_command, _("\
+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"
+INFO_PRINT_ARGS_HELP ("argument variables")));
 
   if (dbx_commands)
     add_com ("func", class_stack, func_command, _("\
diff --git a/gdb/stack.h b/gdb/stack.h
index ca190efa9c..c6924d5237 100644
--- a/gdb/stack.h
+++ b/gdb/stack.h
@@ -31,10 +31,14 @@  typedef void (*iterate_over_block_arg_local_vars_cb) (const char *print_name,
 						      void *cb_data);
 
 void iterate_over_block_arg_vars (const struct block *block,
+				  const gdb::optional<compiled_regex> &preg,
+				  const gdb::optional<compiled_regex> &treg,
 				  iterate_over_block_arg_local_vars_cb cb,
 				  void *cb_data);
 
 void iterate_over_block_local_vars (const struct block *block,
+				    const gdb::optional<compiled_regex> &preg,
+				    const gdb::optional<compiled_regex> &treg,
 				    iterate_over_block_arg_local_vars_cb cb,
 				    void *cb_data);
 
diff --git a/gdb/symfile.c b/gdb/symfile.c
index 20697d9dca..3497093300 100644
--- a/gdb/symfile.c
+++ b/gdb/symfile.c
@@ -53,6 +53,7 @@ 
 #include "elf-bfd.h"
 #include "solib.h"
 #include "remote.h"
+#include "gdb_regex.h"
 #include "stack.h"
 #include "gdb_bfd.h"
 #include "cli/cli-utils.h"
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 0a1caa51fb..5f2afe3582 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"
@@ -4264,6 +4265,50 @@  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;
+  string_file 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)
+    language_def (SYMBOL_LANGUAGE (sym))->la_print_type
+      (sym_type, "", &printed_sym_type_name,
+       -1, 0, &default_ptype_flags);
+  else
+    LA_PRINT_TYPE (sym_type, "", &printed_sym_type_name,
+		   -1, 0, &default_ptype_flags);
+
+  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
@@ -4279,7 +4324,9 @@  sort_search_symbols_remove_dups (std::vector<symbol_search> *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
@@ -4290,6 +4337,7 @@  sort_search_symbols_remove_dups (std::vector<symbol_search> *result)
 
 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;
@@ -4315,6 +4363,7 @@  search_symbols (const char *regexp, enum search_domain kind,
   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);
 
@@ -4364,6 +4413,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.  */
@@ -4462,9 +4518,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
+			     || treg_matches_sym_type_name (*treg, sym)))
+			|| (kind == FUNCTIONS_DOMAIN
+			    && SYMBOL_CLASS (sym) == LOC_BLOCK
+			    && (!treg
+				|| treg_matches_sym_type_name (*treg, sym)))
 			|| (kind == TYPES_DOMAIN
 			    && SYMBOL_CLASS (sym) == LOC_TYPEDEF))))
 	      {
@@ -4495,8 +4555,12 @@  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 /* a minimal symbol has never a type ???? */
+		&& (!preg || 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.  */
@@ -4597,7 +4661,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"};
@@ -4607,13 +4673,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<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)
     {
@@ -4623,7 +4709,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);
@@ -4641,22 +4728,41 @@  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;
+
+  extract_info_print_args ("info variables", &args, &quiet, &regexp, &t_regexp);
+  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;
+
+  extract_info_print_args ("info functions", &args, &quiet, &regexp, &t_regexp);
+  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.  */
@@ -4699,6 +4805,7 @@  rbreak_command (const char *regexp, int from_tty)
 
   std::vector<symbol_search> symbols = search_symbols (regexp,
 						       FUNCTIONS_DOMAIN,
+						       NULL,
 						       nfiles, files);
 
   scoped_rbreak_breakpoints finalize;
@@ -5901,13 +6008,22 @@  _initialize_symtab (void)
     = 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."));
+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"
+INFO_PRINT_ARGS_HELP ("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_info ("functions", info_functions_command,
-	    _("All function names, or those matching REGEXP."));
+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"
+INFO_PRINT_ARGS_HELP ("global and static variables")));
+
+  add_info ("functions", info_functions_command, _("\
+All function names or those matching REGEXPs.\n\
+Usage: info functions [-q] [-t TYPEREGEXP] [NAMEREGEXP]\n\
+Prints the functions.\n"
+INFO_PRINT_ARGS_HELP ("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 eb14f346b9..d413adbeab 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -25,6 +25,7 @@ 
 #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"
@@ -2063,8 +2064,13 @@  private:
 };
 
 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
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index a96f56a06b..69711a034e 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -43,6 +43,7 @@ 
 #include "objfiles.h"
 #include "filenames.h"
 #include "gdbthread.h"
+#include "gdb_regex.h"
 #include "stack.h"
 #include "remote.h"
 #include "source.h"
@@ -1086,6 +1087,7 @@  collection_list::add_local_symbols (struct gdbarch *gdbarch, CORE_ADDR pc,
 {
   const struct block *block;
   struct add_local_symbols_data cb_data;
+  const gdb::optional<compiled_regex> nullreg;
 
   cb_data.collect = this;
   cb_data.gdbarch = gdbarch;
@@ -1105,7 +1107,8 @@  collection_list::add_local_symbols (struct gdbarch *gdbarch, CORE_ADDR pc,
 	  return;
 	}
 
-      iterate_over_block_local_vars (block, do_collect_symbol, &cb_data);
+      iterate_over_block_local_vars (block, nullreg, nullreg,
+				     do_collect_symbol, &cb_data);
       if (cb_data.count == 0)
 	warning (_("No locals found in scope."));
     }
@@ -1119,7 +1122,8 @@  collection_list::add_local_symbols (struct gdbarch *gdbarch, CORE_ADDR pc,
 	  return;
 	}
 
-      iterate_over_block_arg_vars (block, do_collect_symbol, &cb_data);
+      iterate_over_block_arg_vars (block, nullreg, nullreg,
+				   do_collect_symbol, &cb_data);
       if (cb_data.count == 0)
 	warning (_("No args found in scope."));
     }