[review,v3] gdb/mi: Add new commands -symbol-info-{functions,variables,types}

Message ID 20191108005037.8B63F2816A@gnutoolchain-gerrit.osci.io
State New, archived
Headers

Commit Message

Simon Marchi (Code Review) Nov. 8, 2019, 12:50 a.m. UTC
  Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/266
......................................................................

gdb/mi: Add new commands -symbol-info-{functions,variables,types}

Add new MI commands -symbol-info-functions, -symbol-info-variables,
and -symbol-info-types which correspond to the CLI commands 'info
functions', 'info variables', and 'info types' respectively.

gdb/ChangeLog:

	* mi/mi-cmds.c (mi_cmds): Add '-symbol-info-functions',
	'-symbol-info-variables', and '-symbol-info-types'.
	* mi/mi-cmds.h (mi_cmd_symbol_info_functions): Declare.
	(mi_cmd_symbol_info_variables): Declare.
	(mi_cmd_symbol_info_types): Declare.
	* mi/mi-symbol-cmds.c: Add 'source.h' and 'mi-getopt.h' includes.
	(mi_info_one_symbol_details): New function.
	(class mi_symbol_info_emitter): New class.
	(mi_symbol_info): New function.
	(mi_info_functions_or_variables): New function.
	(mi_cmd_symbol_info_functions): New function.
	(mi_cmd_symbol_info_types): New function.
	(mi_cmd_symbol_info_variables): New function.
	* NEWS: Mention new commands.

gdb/testsuite/ChangeLog:

	* gdb.mi/mi-sym-info-1.c: New file.
	* gdb.mi/mi-sym-info-2.c: New file.
	* gdb.mi/mi-sym-info.exp: New file.

gdb/doc/ChangeLog:

	* doc/gdb.texinfo (GDB/MI Symbol Query): Document new MI command
	-symbol-info-functions, -symbol-info-types, and
	-symbol-info-variables.

Change-Id: Ic2fc6a6750bbce91cdde2344791014e5ef45642d
---
M gdb/ChangeLog
M gdb/NEWS
M gdb/doc/ChangeLog
M gdb/doc/gdb.texinfo
M gdb/mi/mi-cmds.c
M gdb/mi/mi-cmds.h
M gdb/mi/mi-symbol-cmds.c
M gdb/testsuite/ChangeLog
A gdb/testsuite/gdb.mi/mi-sym-info-1.c
A gdb/testsuite/gdb.mi/mi-sym-info-2.c
A gdb/testsuite/gdb.mi/mi-sym-info.exp
11 files changed, 828 insertions(+), 7 deletions(-)
  

Comments

Eli Zaretskii Nov. 8, 2019, 10:10 a.m. UTC | #1
> Date: Thu, 7 Nov 2019 19:50:32 -0500
> From: "Andrew Burgess (Code Review)" <gerrit@gnutoolchain-gerrit.osci.io>
> 
> gdb/mi: Add new commands -symbol-info-{functions,variables,types}
> 
> Add new MI commands -symbol-info-functions, -symbol-info-variables,
> and -symbol-info-types which correspond to the CLI commands 'info
> functions', 'info variables', and 'info types' respectively.
> 
> gdb/ChangeLog:
> 
> 	* mi/mi-cmds.c (mi_cmds): Add '-symbol-info-functions',
> 	'-symbol-info-variables', and '-symbol-info-types'.
> 	* mi/mi-cmds.h (mi_cmd_symbol_info_functions): Declare.
> 	(mi_cmd_symbol_info_variables): Declare.
> 	(mi_cmd_symbol_info_types): Declare.
> 	* mi/mi-symbol-cmds.c: Add 'source.h' and 'mi-getopt.h' includes.
> 	(mi_info_one_symbol_details): New function.
> 	(class mi_symbol_info_emitter): New class.
> 	(mi_symbol_info): New function.
> 	(mi_info_functions_or_variables): New function.
> 	(mi_cmd_symbol_info_functions): New function.
> 	(mi_cmd_symbol_info_types): New function.
> 	(mi_cmd_symbol_info_variables): New function.
> 	* NEWS: Mention new commands.
> 
> gdb/testsuite/ChangeLog:
> 
> 	* gdb.mi/mi-sym-info-1.c: New file.
> 	* gdb.mi/mi-sym-info-2.c: New file.
> 	* gdb.mi/mi-sym-info.exp: New file.
> 
> gdb/doc/ChangeLog:
> 
> 	* doc/gdb.texinfo (GDB/MI Symbol Query): Document new MI command
> 	-symbol-info-functions, -symbol-info-types, and
> 	-symbol-info-variables.

OK for the documentation parts.

Thanks.
  

Patch

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 7024c64..1d5059e 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,22 @@ 
 2019-11-01  Andrew Burgess  <andrew.burgess@embecosm.com>
 
+	* mi/mi-cmds.c (mi_cmds): Add '-symbol-info-functions',
+	'-symbol-info-variables', and '-symbol-info-types'.
+	* mi/mi-cmds.h (mi_cmd_symbol_info_functions): Declare.
+	(mi_cmd_symbol_info_variables): Declare.
+	(mi_cmd_symbol_info_types): Declare.
+	* mi/mi-symbol-cmds.c: Add 'source.h' and 'mi-getopt.h' includes.
+	(mi_info_one_symbol_details): New function.
+	(class mi_symbol_info_emitter): New class.
+	(mi_symbol_info): New function.
+	(mi_info_functions_or_variables): New function.
+	(mi_cmd_symbol_info_functions): New function.
+	(mi_cmd_symbol_info_types): New function.
+	(mi_cmd_symbol_info_variables): New function.
+	* NEWS: Mention new commands.
+
+2019-11-01  Andrew Burgess  <andrew.burgess@embecosm.com>
+
 	* symtab.c (symbol_to_info_string): New function, most content
 	moved from print_symbol_info, but updated to return a std::string.
 	(print_symbol_info): Update to use symbol_to_info_string and print
diff --git a/gdb/NEWS b/gdb/NEWS
index dc63179..a47a22a 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -344,6 +344,10 @@ 
   These can be used to catch C++ exceptions in a similar fashion to
   the CLI commands 'catch throw', 'catch rethrow', and 'catch catch'.
 
+-symbol-info-functions, -symbol-info-types, and -symbol-info-variables
+  These commands are the MI equivalent of the CLI commands 'info
+  functions', 'info types', and 'info variables' respectively.
+
 * Other MI changes
 
  ** The default version of the MI interpreter is now 3 (-i=mi3).
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index ce89ee4..af0478e 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,3 +1,9 @@ 
+2019-11-01  Andrew Burgess  <andrew.burgess@embecosm.com>
+
+	* doc/gdb.texinfo (GDB/MI Symbol Query): Document new MI command
+	-symbol-info-functions, -symbol-info-types, and
+	-symbol-info-variables.
+
 2019-10-31  Andrew Burgess  <andrew.burgess@embecosm.com>
 
 	* gdb.texinfo (Symbols): Document new 'info module variables' and
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 70e4be1..66dbb22 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -33852,27 +33852,283 @@ 
 
 @subsubheading Example
 N.A.
+@end ignore
 
-
-@subheading The @code{-symbol-info-function} Command
-@findex -symbol-info-function
+@subheading The @code{-symbol-info-functions} Command
+@findex -symbol-info-functions
+@anchor{-symbol-info-functions}
 
 @subsubheading Synopsis
 
 @smallexample
- -symbol-info-function
+ -symbol-info-functions [--include-nondebug]
+                        [--type @var{type_regexp}]
+                        [--name @var{name_regexp}]
 @end smallexample
 
-Show which function the symbol lives in.
+@noindent
+Return a list containing the names and types for all global functions
+taken from the debug information.  The functions are grouped by source
+file, and shown with the line number on which each function is
+defined.
+
+The @code{--include-nondebug} option causes the output to include
+code symbols from the symbol table.
+
+The options @code{--type} and @code{--name} allow the symbols returned
+to be filtered based on either the name of the function, or the type
+signature of the function.
 
 @subsubheading @value{GDBN} Command
 
-@samp{gdb_get_function} in @code{gdbtk}.
+The corresponding @value{GDBN} command is @samp{info functions}.
 
 @subsubheading Example
-N.A.
+@smallexample
+@group
+(gdb)
+-symbol-info-functions
+^done,symbols=
+  @{debug=
+    [@{filename="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      symbols=[@{line="36", name="f4", type="void (int *)",
+                description="void f4(int *);"@},
+               @{line="42", name="main", type="int ()",
+                description="int main();"@},
+               @{line="30", name="f1", type="my_int_t (int, int)",
+                description="static my_int_t f1(int, int);"@}]@},
+     @{filename="/project/gdb/testsuite/gdb.mi/mi-sym-info-2.c",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-2.c",
+      symbols=[@{line="33", name="f2", type="float (another_float_t)",
+                description="float f2(another_float_t);"@},
+               @{line="39", name="f3", type="int (another_int_t)",
+                description="int f3(another_int_t);"@},
+               @{line="27", name="f1", type="another_float_t (int)",
+                description="static another_float_t f1(int);"@}]@}]@}
+@end group
+@group
+(gdb)
+-symbol-info-functions --name f1
+^done,symbols=
+  @{debug=
+    [@{filename="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      symbols=[@{line="30", name="f1", type="my_int_t (int, int)",
+                description="static my_int_t f1(int, int);"@}]@},
+     @{filename="/project/gdb/testsuite/gdb.mi/mi-sym-info-2.c",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-2.c",
+      symbols=[@{line="27", name="f1", type="another_float_t (int)",
+                description="static another_float_t f1(int);"@}]@}]@}
+@end group
+@group
+(gdb)
+-symbol-info-functions --type void
+^done,symbols=
+  @{debug=
+    [@{filename="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      symbols=[@{line="36", name="f4", type="void (int *)",
+                description="void f4(int *);"@}]@}]@}
+@end group
+@group
+(gdb)
+-symbol-info-functions --include-nondebug
+^done,symbols=
+  @{debug=
+    [@{filename="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      symbols=[@{line="36", name="f4", type="void (int *)",
+                description="void f4(int *);"@},
+               @{line="42", name="main", type="int ()",
+                description="int main();"@},
+               @{line="30", name="f1", type="my_int_t (int, int)",
+                description="static my_int_t f1(int, int);"@}]@},
+     @{filename="/project/gdb/testsuite/gdb.mi/mi-sym-info-2.c",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-2.c",
+      symbols=[@{line="33", name="f2", type="float (another_float_t)",
+                description="float f2(another_float_t);"@},
+               @{line="39", name="f3", type="int (another_int_t)",
+                description="int f3(another_int_t);"@},
+               @{line="27", name="f1", type="another_float_t (int)",
+                description="static another_float_t f1(int);"@}]@}],
+   nondebug=
+    [@{address="0x0000000000400398",name="_init"@},
+     @{address="0x00000000004003b0",name="_start"@},
+      ...
+    ]@}
+@end group
+@end smallexample
 
+@subheading The @code{-symbol-info-types} Command
+@findex -symbol-info-types
+@anchor{-symbol-info-types}
 
+@subsubheading Synopsis
+
+@smallexample
+ -symbol-info-types [--name @var{name_regexp}]
+@end smallexample
+
+@noindent
+Return a list of all defined types.  The types are grouped by source
+file, and shown with the line number on which each user defined type
+is defined.  Some base types are not defined in the source code but
+are added to the debug information by the compiler, for example
+@code{int}, @code{float}, etc.; these types do not have an associated
+line number.
+
+The option @code{--name} allows the list of types returned to be
+filtered by name.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{info types}.
+
+@subsubheading Example
+@smallexample
+@group
+(gdb)
+-symbol-info-types
+^done,symbols=
+  @{debug=
+     [@{filename="gdb.mi/mi-sym-info-1.c",
+       fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+       symbols=[@{name="float"@},
+                @{name="int"@},
+                @{line="27",name="typedef int my_int_t;"@}]@},
+      @{filename="gdb.mi/mi-sym-info-2.c",
+       fullname="/project/gdb.mi/mi-sym-info-2.c",
+       symbols=[@{line="24",name="typedef float another_float_t;"@},
+                @{line="23",name="typedef int another_int_t;"@},
+                @{name="float"@},
+                @{name="int"@}]@}]@}
+@end group
+@group
+(gdb)
+-symbol-info-types --name _int_
+^done,symbols=
+  @{debug=
+     [@{filename="gdb.mi/mi-sym-info-1.c",
+       fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+       symbols=[@{line="27",name="typedef int my_int_t;"@}]@},
+      @{filename="gdb.mi/mi-sym-info-2.c",
+       fullname="/project/gdb.mi/mi-sym-info-2.c",
+       symbols=[@{line="23",name="typedef int another_int_t;"@}]@}]@}
+@end group
+@end smallexample
+
+@subheading The @code{-symbol-info-variables} Command
+@findex -symbol-info-variables
+@anchor{-symbol-info-variables}
+
+@subsubheading Synopsis
+
+@smallexample
+ -symbol-info-variables [--include-nondebug]
+                        [--type @var{type_regexp}]
+                        [--name @var{name_regexp}]
+@end smallexample
+
+@noindent
+Return a list containing the names and types for all global variables
+taken from the debug information.  The variables are grouped by source
+file, and shown with the line number on which each variable is
+defined.
+
+The @code{--include-nondebug} option causes the output to include
+data symbols from the symbol table.
+
+The options @code{--type} and @code{--name} allow the symbols returned
+to be filtered based on either the name of the variable, or the type
+of the variable.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{info variables}.
+
+@subsubheading Example
+@smallexample
+@group
+(gdb)
+-symbol-info-variables
+^done,symbols=
+  @{debug=
+    [@{filename="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      symbols=[@{line="25",name="global_f1",type="float",
+                description="static float global_f1;"@},
+               @{line="24",name="global_i1",type="int",
+                description="static int global_i1;"@}]@},
+     @{filename="/project/gdb/testsuite/gdb.mi/mi-sym-info-2.c",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-2.c",
+      symbols=[@{line="21",name="global_f2",type="int",
+                description="int global_f2;"@},
+               @{line="20",name="global_i2",type="int",
+                description="int global_i2;"@},
+               @{line="19",name="global_f1",type="float",
+                description="static float global_f1;"@},
+               @{line="18",name="global_i1",type="int",
+                description="static int global_i1;"@}]@}]@}
+@end group
+@group
+(gdb)
+-symbol-info-variables --name f1
+^done,symbols=
+  @{debug=
+    [@{filename="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      symbols=[@{line="25",name="global_f1",type="float",
+                description="static float global_f1;"@}]@},
+     @{filename="/project/gdb/testsuite/gdb.mi/mi-sym-info-2.c",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-2.c",
+      symbols=[@{line="19",name="global_f1",type="float",
+                description="static float global_f1;"@}]@}]@}
+@end group
+@group
+(gdb)
+-symbol-info-variables --type float
+^done,symbols=
+  @{debug=
+    [@{filename="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      symbols=[@{line="25",name="global_f1",type="float",
+                description="static float global_f1;"@}]@},
+     @{filename="/project/gdb/testsuite/gdb.mi/mi-sym-info-2.c",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-2.c",
+      symbols=[@{line="19",name="global_f1",type="float",
+                description="static float global_f1;"@}]@}]@}
+@end group
+@group
+(gdb)
+-symbol-info-variables --include-nondebug
+^done,symbols=
+  @{debug=
+    [@{filename="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+      symbols=[@{line="25",name="global_f1",type="float",
+                description="static float global_f1;"@},
+               @{line="24",name="global_i1",type="int",
+                description="static int global_i1;"@}]@},
+     @{filename="/project/gdb/testsuite/gdb.mi/mi-sym-info-2.c",
+      fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-2.c",
+      symbols=[@{line="21",name="global_f2",type="int",
+                description="int global_f2;"@},
+               @{line="20",name="global_i2",type="int",
+                description="int global_i2;"@},
+               @{line="19",name="global_f1",type="float",
+                description="static float global_f1;"@},
+               @{line="18",name="global_i1",type="int",
+                description="static int global_i1;"@}]@}],
+   nondebug=
+    [@{address="0x00000000004005d0",name="_IO_stdin_used"@},
+     @{address="0x00000000004005d8",name="__dso_handle"@}
+      ...
+    ]@}
+@end group
+@end smallexample
+
+@ignore
 @subheading The @code{-symbol-info-line} Command
 @findex -symbol-info-line
 
diff --git a/gdb/mi/mi-cmds.c b/gdb/mi/mi-cmds.c
index 37eab01..df9f25f 100644
--- a/gdb/mi/mi-cmds.c
+++ b/gdb/mi/mi-cmds.c
@@ -151,6 +151,9 @@ 
   DEF_MI_CMD_MI_1 ("stack-select-frame", mi_cmd_stack_select_frame,
 		   &mi_suppress_notification.user_selected_context),
   DEF_MI_CMD_MI ("symbol-list-lines", mi_cmd_symbol_list_lines),
+  DEF_MI_CMD_MI ("symbol-info-functions", mi_cmd_symbol_info_functions),
+  DEF_MI_CMD_MI ("symbol-info-variables", mi_cmd_symbol_info_variables),
+  DEF_MI_CMD_MI ("symbol-info-types", mi_cmd_symbol_info_types),
   DEF_MI_CMD_CLI ("target-attach", "attach", 1),
   DEF_MI_CMD_MI ("target-detach", mi_cmd_target_detach),
   DEF_MI_CMD_CLI ("target-disconnect", "disconnect", 0),
diff --git a/gdb/mi/mi-cmds.h b/gdb/mi/mi-cmds.h
index 91ce4cd..c2fd7d3 100644
--- a/gdb/mi/mi-cmds.h
+++ b/gdb/mi/mi-cmds.h
@@ -94,6 +94,9 @@ 
 extern mi_cmd_argv_ftype mi_cmd_stack_list_variables;
 extern mi_cmd_argv_ftype mi_cmd_stack_select_frame;
 extern mi_cmd_argv_ftype mi_cmd_symbol_list_lines;
+extern mi_cmd_argv_ftype mi_cmd_symbol_info_functions;
+extern mi_cmd_argv_ftype mi_cmd_symbol_info_types;
+extern mi_cmd_argv_ftype mi_cmd_symbol_info_variables;
 extern mi_cmd_argv_ftype mi_cmd_target_detach;
 extern mi_cmd_argv_ftype mi_cmd_target_file_get;
 extern mi_cmd_argv_ftype mi_cmd_target_file_put;
diff --git a/gdb/mi/mi-symbol-cmds.c b/gdb/mi/mi-symbol-cmds.c
index 63142e8..46086bf 100644
--- a/gdb/mi/mi-symbol-cmds.c
+++ b/gdb/mi/mi-symbol-cmds.c
@@ -21,6 +21,8 @@ 
 #include "symtab.h"
 #include "objfiles.h"
 #include "ui-out.h"
+#include "source.h"
+#include "mi-getopt.h"
 
 /* Print the list of all pc addresses and lines of code for the
    provided (full or base) source file name.  The entries are sorted
@@ -59,3 +61,307 @@ 
       uiout->field_signed ("line", SYMTAB_LINETABLE (s)->item[i].line);
     }
 }
+
+/* Used by the -symbol-info-* and -symbol-info-module-* commands to print
+   information about the symbol SYM in a block of index BLOCK (either
+   GLOBAL_BLOCK or STATIC_BLOCK).  KIND is the kind of symbol we searched
+   for in order to find SYM, which impact which fields are displayed in the
+   results.  */
+
+static void
+mi_info_one_symbol_details (enum search_domain kind,
+			    struct symbol *sym, int block)
+{
+  struct ui_out *uiout = current_uiout;
+
+  ui_out_emit_tuple tuple_emitter (uiout, NULL);
+  if (SYMBOL_LINE (sym) != 0)
+    uiout->field_unsigned ("line", SYMBOL_LINE (sym));
+  uiout->field_string ("name", SYMBOL_PRINT_NAME (sym));
+
+  if (kind == FUNCTIONS_DOMAIN || kind == VARIABLES_DOMAIN)
+    {
+      string_file tmp_stream;
+      type_print (SYMBOL_TYPE (sym), "", &tmp_stream, -1);
+      uiout->field_string ("type", tmp_stream.string ());
+
+      std::string str = symbol_to_info_string (sym, block, kind);
+      uiout->field_string ("description", str.c_str ());
+    }
+}
+
+/* This class is used to produce the nested structure of tuples and lists
+   required to present the results of the MI_SYMBOL_INFO function.  */
+class mi_symbol_info_emitter
+{
+  /* When printing debug symbols we need to track the last symtab so we can
+     spot when we have entered a new one.  */
+  const symtab *m_last_symtab;
+
+  /* The ui_out to which output will be sent.  */
+  struct ui_out *m_uiout;
+
+  /* The outer container for all the matched symbols.  */
+  ui_out_emit_tuple m_outer_symbols;
+
+  /* The order of these optional emitters is critical as they will be
+     deleted in reverse order, which is important as these are popped from
+     the uiout stack as they are destroyed.  */
+  gdb::optional<ui_out_emit_list> m_debug_emitter;
+  gdb::optional<ui_out_emit_tuple> m_symtab_emitter;
+  gdb::optional<ui_out_emit_list> m_symbols_emitter;
+  gdb::optional<ui_out_emit_list> m_nondebug_emitter;
+
+  /* Called when we might want to print our first nondebug symbol in order
+     to shutdown any debug symbol printing that might be in progress.  */
+  void maybe_finish_debug_output ()
+  {
+    /* If the debug emitter is in use.  */
+    if (m_debug_emitter.has_value ())
+      {
+	/* Then we should have a symbols list inside a symtab tuple also
+	   currently in use.  */
+	gdb_assert (m_symbols_emitter.has_value ());
+	gdb_assert (m_symtab_emitter.has_value ());
+
+	/* Shut down the symbols list, symtab tuple, and debug list
+	   emitters (in that order).  We are now back to the level of the
+	   outer_symbols tuple ready to (possibly) start a nondebug list,
+	   though that is not done here.  */
+	m_symbols_emitter.reset ();
+	m_symtab_emitter.reset ();
+	m_debug_emitter.reset ();
+      }
+  }
+
+  /* Return true if the nondebug emitter has been put in place.  */
+  bool have_started_nondebug_symbol_output () const
+  {
+    return m_nondebug_emitter.has_value ();
+  }
+
+  /* Called before we print every nondebug symbol.  If this is the first
+     nondebug symbol to be printed then it will setup the emitters required
+     to print nondebug symbols.  */
+  void maybe_start_nondebug_symbol_output ()
+  {
+    if (!have_started_nondebug_symbol_output ())
+      m_nondebug_emitter.emplace (m_uiout, "nondebug");
+  }
+
+  /* Actually output one nondebug symbol, puts a tuple emitter in place
+     and then outputs the fields for this msymbol.  */
+  void output_nondebug_symbol (const struct bound_minimal_symbol &msymbol)
+  {
+    struct gdbarch *gdbarch = get_objfile_arch (msymbol.objfile);
+    ui_out_emit_tuple tuple_emitter (m_uiout, NULL);
+    m_uiout->field_core_addr ("address", gdbarch,
+			      BMSYMBOL_VALUE_ADDRESS (msymbol));
+    m_uiout->field_string ("name", MSYMBOL_PRINT_NAME (msymbol.minsym));
+  }
+
+  /* Called before we print every debug symbol.  If this is the first debug
+     symbol to be printed then it will setup the top level of emitters
+     required to print debug symbols.  */
+  void maybe_start_debug_symbol_output ()
+  {
+    if (!m_debug_emitter.has_value ())
+      m_debug_emitter.emplace (m_uiout, "debug");
+  }
+
+  /* Called before we print every debug symbol, S is the symtab for the
+     symbol to be printed.  If S is different to the last symtab we printed
+     for then we close down the emitters for the last symtab, and create
+     new emitters for this new symtab.  */
+  void setup_emitters_for_symtab (symtab *s)
+  {
+    if (s != m_last_symtab)
+      {
+	/* Reset a possible previous symbol list within a symtab.  */
+	m_symbols_emitter.reset ();
+	m_symtab_emitter.reset ();
+
+	/* Start a new symtab and symbol list within the symtab.  */
+	m_symtab_emitter.emplace (m_uiout, nullptr);
+	m_uiout->field_string ("filename",
+			       symtab_to_filename_for_display (s));
+	m_uiout->field_string ("fullname", symtab_to_fullname (s));
+	m_symbols_emitter.emplace (m_uiout, "symbols");
+
+	/* Record the current symtab.  */
+	m_last_symtab = s;
+      }
+  }
+
+public:
+  /* Constructor.  */
+  mi_symbol_info_emitter (struct ui_out *uiout)
+    : m_last_symtab (nullptr),
+      m_uiout (uiout),
+      m_outer_symbols (uiout, "symbols")
+  { /* Nothing.  */ }
+
+  /* Output P a symbol found by searching for symbols of type KIND.  */
+  void output (const symbol_search &p, enum search_domain kind)
+  {
+    if (p.msymbol.minsym != NULL)
+      {
+	/* If this is the first nondebug symbol, and we have previous
+	   outputted a debug symbol then we need to close down all of the
+	   emitters related to printing debug symbols.  */
+	maybe_finish_debug_output ();
+
+	/* If this is the first nondebug symbol then we need to create the
+	   emitters related to printing nondebug symbols.  */
+	maybe_start_nondebug_symbol_output ();
+
+	/* We are no safe to emit the nondebug symbol.  */
+	output_nondebug_symbol (p.msymbol);
+      }
+    else
+      {
+	/* All debug symbols should appear in the list before all
+	   non-debug symbols.  */
+	gdb_assert (!have_started_nondebug_symbol_output ());
+
+	/* If this is the first debug symbol then we need to create the
+	   outer level of emitters related to printing debug symbols.  */
+	maybe_start_debug_symbol_output ();
+
+	/* Ensure the correct emitters are in place to emit this debug
+	   symbol.  */
+	setup_emitters_for_symtab (symbol_symtab (p.symbol));
+
+	/* Emit information for this debug symbol.  */
+	mi_info_one_symbol_details (kind, p.symbol, p.block);
+      }
+  }
+};
+
+/* This is the guts of the commands '-symbol-info-functions',
+   '-symbol-info-variables', and '-symbol-info-types'.  It calls
+   search_symbols to find all matches and then prints the matching
+   [m]symbols in an MI structured format.  This is similar to
+   symtab_symbol_info in symtab.c.  All the arguments are used to
+   initialise a SEARCH_SYMBOLS_SPEC, see symtab.h for a description of
+   their meaning.  */
+
+static void
+mi_symbol_info (enum search_domain kind, const char *regexp,
+		const char *t_regexp, bool exclude_minsyms)
+{
+  /* Must make sure that if we're interrupted, symbols gets freed.  */
+  global_symbol_searcher sym_search (kind, regexp, t_regexp, exclude_minsyms);
+  std::vector<symbol_search> symbols = sym_search.search ();
+
+  mi_symbol_info_emitter emitter (current_uiout);
+  for (const symbol_search &p : symbols)
+    {
+      QUIT;
+      emitter.output (p, kind);
+    }
+}
+
+/* Helper for mi_cmd_symbol_info_{functions,variables} - depending on KIND.
+   Processes command line options from ARGV and ARGC.  */
+
+static void
+mi_info_functions_or_variables (enum search_domain kind, char **argv, int argc)
+{
+  const char *regexp = nullptr;
+  const char *t_regexp = nullptr;
+  bool exclude_minsyms = true;
+
+  enum opt
+    {
+     INCLUDE_NONDEBUG_OPT, TYPE_REGEXP_OPT, NAME_REGEXP_OPT
+    };
+  static const struct mi_opt opts[] =
+  {
+    {"-include-nondebug" , INCLUDE_NONDEBUG_OPT, 0},
+    {"-type", TYPE_REGEXP_OPT, 1},
+    {"-name", NAME_REGEXP_OPT, 1},
+    { 0, 0, 0 }
+  };
+
+  int oind = 0;
+  char *oarg = nullptr;
+
+  while (1)
+    {
+      const char *cmd_string
+	= ((kind == FUNCTIONS_DOMAIN)
+	   ? "-symbol-info-functions" : "-symbol-info-variables");
+      int opt = mi_getopt (cmd_string, argc, argv, opts, &oind, &oarg);
+      if (opt < 0)
+	break;
+      switch ((enum opt) opt)
+	{
+	case INCLUDE_NONDEBUG_OPT:
+	  exclude_minsyms = false;
+	  break;
+	case TYPE_REGEXP_OPT:
+	  t_regexp = oarg;
+	  break;
+	case NAME_REGEXP_OPT:
+	  regexp = oarg;
+	  break;
+	}
+    }
+
+  mi_symbol_info (kind, regexp, t_regexp, exclude_minsyms);
+}
+
+/* Implement -symbol-info-functions command.  */
+
+void
+mi_cmd_symbol_info_functions (const char *command, char **argv, int argc)
+{
+  mi_info_functions_or_variables (FUNCTIONS_DOMAIN, argv, argc);
+}
+
+/* Implement -symbol-info-types command.  */
+
+void
+mi_cmd_symbol_info_types (const char *command, char **argv, int argc)
+{
+  const char *regexp = nullptr;
+
+  enum opt
+    {
+     NAME_REGEXP_OPT
+    };
+  static const struct mi_opt opts[] =
+  {
+    {"-name", NAME_REGEXP_OPT, 1},
+    { 0, 0, 0 }
+  };
+
+  int oind = 0;
+  char *oarg = nullptr;
+
+  while (1)
+    {
+      int opt = mi_getopt ("-symbol-info-types", argc, argv, opts,
+			   &oind, &oarg);
+      if (opt < 0)
+	break;
+      switch ((enum opt) opt)
+	{
+	case NAME_REGEXP_OPT:
+	  regexp = oarg;
+	  break;
+	}
+    }
+
+  mi_symbol_info (TYPES_DOMAIN, regexp, nullptr, true);
+}
+
+/* Implement -symbol-info-variables command.  */
+
+void
+mi_cmd_symbol_info_variables (const char *command, char **argv, int argc)
+{
+  mi_info_functions_or_variables (VARIABLES_DOMAIN, argv, argc);
+}
+
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 9b7bcf6..d929ed3 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,9 @@ 
+2019-11-01  Andrew Burgess  <andrew.burgess@embecosm.com>
+
+	* gdb.mi/mi-sym-info-1.c: New file.
+	* gdb.mi/mi-sym-info-2.c: New file.
+	* gdb.mi/mi-sym-info.exp: New file.
+
 2019-11-02  Tom de Vries  <tdevries@suse.de>
 
 	* gdb.base/advance.exp: Drop superfluous 3rd argument to gdb_test.
diff --git a/gdb/testsuite/gdb.mi/mi-sym-info-1.c b/gdb/testsuite/gdb.mi/mi-sym-info-1.c
new file mode 100644
index 0000000..9b6dc73
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-sym-info-1.c
@@ -0,0 +1,48 @@ 
+/* Copyright 2019 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Function and variables declared in mi-sym-info-2.c.  */
+extern float f2 (float arg);
+extern int f3 (int arg);
+extern int global_i2;
+extern float global_f2;
+
+static int global_i1;
+static float global_f1;
+
+typedef int my_int_t;
+
+static my_int_t
+f1 (int arg1, int arg2)
+{
+  return arg1 + arg2;
+}
+
+void
+f4 (int *arg)
+{
+  (*arg)++;
+}
+
+int
+main ()
+{
+  int v = f3 (4);
+  f4 (&v);
+  float tmp = f2 (1.0);
+  return f1 (3, v) + ((int) tmp);
+}
diff --git a/gdb/testsuite/gdb.mi/mi-sym-info-2.c b/gdb/testsuite/gdb.mi/mi-sym-info-2.c
new file mode 100644
index 0000000..c80877d
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-sym-info-2.c
@@ -0,0 +1,43 @@ 
+/* Copyright 2019 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+static int global_i1;
+static float global_f1;
+int global_i2;
+int global_f2;
+
+typedef int another_int_t;
+typedef float another_float_t;
+
+static another_float_t
+f1 (int arg)
+{
+  return (float) arg;
+}
+
+float
+f2 (another_float_t arg)
+{
+  return arg + f1 (1);
+}
+
+int
+f3 (another_int_t arg)
+{
+  return arg + 2;
+}
+
diff --git a/gdb/testsuite/gdb.mi/mi-sym-info.exp b/gdb/testsuite/gdb.mi/mi-sym-info.exp
new file mode 100644
index 0000000..33fe865
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-sym-info.exp
@@ -0,0 +1,129 @@ 
+# Copyright 2019 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test -symbol-info-functions, -symbol-info-variables, and
+# -symbol-info-types.
+
+load_lib mi-support.exp
+set MIFLAGS "-i=mi"
+
+standard_testfile mi-sym-info-1.c mi-sym-info-2.c
+
+if {[prepare_for_testing "failed to prepare" ${testfile} \
+	 [list $srcfile $srcfile2] {debug}]} {
+    return -1
+}
+
+gdb_exit
+if {[mi_gdb_start]} {
+    continue
+}
+
+mi_run_to_main
+
+set qstr "\"\[^\"\]+\""
+set fun_re "\{line=\"$decimal\",name=${qstr},type=${qstr},description=${qstr}\}"
+set type_re "\{(?:line=\"$decimal\",)*name=${qstr}\}"
+set sym_list "\\\[${fun_re}(?:,$fun_re)*\\\]"
+set type_sym_list "\\\[${type_re}(?:,$type_re)*\\\]"
+set symtab_re \
+    "\{filename=${qstr},fullname=${qstr},symbols=${sym_list}\}"
+set symtab_type_re \
+    "\{filename=${qstr},fullname=${qstr},symbols=${type_sym_list}\}"
+set debug_only_syms \
+    "symbols=\{debug=\\\[${symtab_re}(?:,${symtab_re})*\\\]\}"
+set all_syms \
+    "symbols=\{debug=\\\[${symtab_re}(?:,${symtab_re})*\\\],nondebug=\\\[.*\\\]\}"
+set type_syms \
+    "symbols=\{debug=\\\[${symtab_type_re}(?:,${symtab_type_re})*\\\]\}"
+
+# Fetch all functions, variables and types without any non-debug
+# symbols.
+mi_gdb_test "111-symbol-info-functions" \
+    "111\\^done,${debug_only_syms}" \
+    "List all functions from debug information only"
+
+mi_gdb_test "112-symbol-info-variables" \
+    "112\\^done,${debug_only_syms}" \
+    "List all variables from debug information only"
+
+mi_gdb_test "113-symbol-info-types" \
+    "113\\^done,${type_syms}" \
+    "List all types"
+
+# Fetch functions and variables but also grab the non-debug symbols
+# (from the symbol table).  There's often so much output output from
+# this command that we overflow expect's buffers, avoid this by
+# fetching the output piece by piece.
+set testname "List all functions"
+gdb_test_multiple "114-symbol-info-functions --include-nondebug" ${testname} {
+    -re "114\\^done,symbols=\{debug=\\\[${symtab_re}(?:,${symtab_re})*\\\],nondebug=\\\[" {
+	exp_continue
+    }
+
+    -re "\{address=${qstr},name=${qstr}\}," {
+	exp_continue
+    }
+
+    -re "\{address=${qstr},name=${qstr}\}\\\]\}\r\n${mi_gdb_prompt}$" {
+	pass ${testname}
+    }
+}
+
+set testname "List all variables"
+gdb_test_multiple "115-symbol-info-variables --include-nondebug" ${testname} {
+    -re "115\\^done,symbols=\{debug=\\\[${symtab_re}(?:,${symtab_re})*\\\],nondebug=\\\[" {
+	verbose -log "Got the first part of the input"
+	exp_continue
+    }
+
+    -re "\{address=${qstr},name=${qstr}\}," {
+	exp_continue
+    }
+
+    -re "\{address=${qstr},name=${qstr}\}\\\]\}\r\n${mi_gdb_prompt}$" {
+	pass ${testname}
+    }
+}
+
+# Filter functions by name and type.
+set lineno [gdb_get_line_number "f3 (another_int_t arg)" ${srcfile2}]
+mi_gdb_test "116-symbol-info-functions --name f3" \
+    "116\\^done,symbols=\{debug=\\\[\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"39\",name=\"f3\",type=\"int \\(another_int_t\\)\",description=\"int f3\\(another_int_t\\);\"\}\\\]\}\\\]\}" \
+    "List all functions matching pattern f3"
+
+set lineno [gdb_get_line_number "f4 (int *arg)" ${srcfile}]
+mi_gdb_test "117-symbol-info-functions --type void" \
+    "117\\^done,symbols=\{debug=\\\[\{filename=\"\[^\"\]+$srcfile\",fullname=\"\[^\"\]+$srcfile\",symbols=\\\[\{line=\"36\",name=\"f4\",type=\"void \\(int \\*\\)\",description=\"void f4\\(int \\*\\);\"\}\\\]\}\\\]\}" \
+    "List all functions matching type void"
+
+# Filter variables by name and type.
+set lineno [gdb_get_line_number "int global_f2;" ${srcfile2}]
+mi_gdb_test "118-symbol-info-variables --name global_f2" \
+    "118\\^done,symbols=\{debug=\\\[\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"21\",name=\"global_f2\",type=\"int\",description=\"int global_f2;\"\}\\\]\}\\\]\}" \
+    "List all variables matching pattern global_f2"
+
+set lineno1 [gdb_get_line_number "static float global_f1;" ${srcfile}]
+set lineno2 [gdb_get_line_number "static float global_f1;" ${srcfile2}]
+mi_gdb_test "119-symbol-info-variables --type float" \
+    "119\\^done,symbols=\{debug=\\\[\{filename=\"\[^\"\]+$srcfile\",fullname=\"\[^\"\]+$srcfile\",symbols=\\\[\{line=\"25\",name=\"global_f1\",type=\"float\",description=\"static float global_f1;\"\}\\\]\},\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"19\",name=\"global_f1\",type=\"float\",description=\"static float global_f1;\"\}\\\]\}\\\]\}" \
+    "List all variables matching type float"
+
+# Fetch types, filtering by name.
+set lineno1 [gdb_get_line_number "typedef int my_int_t;" ${srcfile}]
+set lineno2 [gdb_get_line_number "typedef int another_int_t;" ${srcfile2}]
+mi_gdb_test "120-symbol-info-types --name _int_" \
+    "120\\^done,symbols=\{debug=\\\[\{filename=\"\[^\"\]+$srcfile\",fullname=\"\[^\"\]+$srcfile\",symbols=\\\[\{line=\"27\",name=\"my_int_t\"\}\\\]\},\{filename=\"\[^\"\]+$srcfile2\",fullname=\"\[^\"\]+$srcfile2\",symbols=\\\[\{line=\"23\",name=\"another_int_t\"\}\\\]\}\\\]\}" \
+    "List all types matching _int_"