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

Andrew Burgess
2019-09-26T23:09:53Z

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: 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_symbol_info): New function.
(mi_info_functions_or_variables): New function.
(mi_cmd_symbol_info_functions): New function.
(mi_cmd_symbol_info_variables): New function.
(mi_cmd_symbol_info_types): 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.
---
gdb/ChangeLog | 15 +++
gdb/NEWS | 4 +
gdb/doc/ChangeLog | 6 +
gdb/doc/gdb.texinfo | 212 ++++++++++++++++++++++++++++++++++-
gdb/mi/mi-cmds.c | 3 +
gdb/mi/mi-cmds.h | 3 +
gdb/mi/mi-symbol-cmds.c | 195 ++++++++++++++++++++++++++++++++
gdb/testsuite/ChangeLog | 6 +
gdb/testsuite/gdb.mi/mi-sym-info-1.c | 48 ++++++++
gdb/testsuite/gdb.mi/mi-sym-info-2.c | 43 +++++++
gdb/testsuite/gdb.mi/mi-sym-info.exp | 179 +++++++++++++++++++++++++++++
11 files changed, 708 insertions(+), 6 deletions(-)
create mode 100644 gdb/testsuite/gdb.mi/mi-sym-info-1.c
create mode 100644 gdb/testsuite/gdb.mi/mi-sym-info-2.c
create mode 100644 gdb/testsuite/gdb.mi/mi-sym-info.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index 779fd91d3a6..9c1d08a24c4 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -302,6 +302,10 @@ focus, winheight, +, -, >, <
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/gdb.texinfo b/gdb/doc/gdb.texinfo
index f2713c03960..59c84f029c2 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -33694,27 +33694,227 @@

@subsubheading Example
N.A.
+@end ignore
+
+@subheading The @code{-symbol-info-functions} Command
+@findex -symbol-info-functions
+@anchor{-symbol-info-functions}
+
+@subsubheading Synopsis

+@smallexample
+ -symbol-info-functions [--include-nondebug] [--type @var{type_regexp}]
+ [--name @var{name_regexp}]
+@end smallexample

-@subheading The @code{-symbol-info-function} Command
-@findex -symbol-info-function
+@noindent
+Returns a list containing the names and types for all global functions
+taken from the debug information. The functions are grouped by source
+file, and the line number on which each function is defined is given.
+
+When @code{--include-nondebug} is passed then the output also includes
+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
+
+The corresponding @value{GDBN} command is @samp{info functions}.
+
+@subsubheading Example
+@smallexample
+(gdb)
+-symbol-info-functions
+^done,symbols=
+ @{debug=
+ [@{filename="gdb.mi/mi-sym-info-1.c",
+ fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+ definitions=[@{line="36",definition="void f4(int *);"@},
+ @{line="42",definition="int main();"@},
+ @{line="30",definition="static my_int_t f1(int, int);"@}]@},
+ @{filename="gdb.mi/mi-sym-info-2.c",
+ fullname="/project/gdb.mi/mi-sym-info-2.c",
+ definitions=[@{line="33",definition="float f2(another_float_t);"@},
+ @{line="39",definition="int f3(another_int_t);"@},
+ @{line="27",definition="static another_float_t f1(int);"@}]@}]@}
+(gdb)
+-symbol-info-functions --name f1
+^done,symbols=
+ @{debug=
+ [@{filename="gdb.mi/mi-sym-info-1.c",
+ fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+ definitions=[@{line="30",definition="static my_int_t f1(int, int);"@}]@},
+ @{filename="gdb.mi/mi-sym-info-2.c",
+ fullname="/project/gdb.mi/mi-sym-info-2.c",
+ definitions=[@{line="27",definition="static another_float_t f1(int);"@}]@}]@}
+(gdb)
+-symbol-info-functions --type void
+^done,symbols=
+ @{debug=
+ [@{filename="gdb.mi/mi-sym-info-1.c",
+ fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+ definitions=[@{line="36",definition="void f4(int *);"@}]@}]@}
+(gdb)
+-symbol-info-functions --include-nondebug
+^done,symbols=
+ @{debug=
+ [@{filename="gdb.mi/mi-sym-info-1.c",
+ fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+ definitions=[@{line="36",definition="void f4(int *);"@},
+ @{line="42",definition="int main();"@},
+ @{line="30",definition="static my_int_t f1(int, int);"@}]@},
+ @{filename="gdb.mi/mi-sym-info-2.c",
+ fullname="/project/gdb.mi/mi-sym-info-2.c",
+ definitions=[@{line="33",definition="float f2(another_float_t);"@},
+ @{line="39",definition="int f3(another_int_t);"@},
+ @{line="27",definition="static another_float_t f1(int);"@}]@}],
+ nondebug=
+ [@{address="0x0000000000400398",name="_init"@},
+ @{address="0x00000000004003b0",name="_start"@},
+ ...
+ ]@}
+@end smallexample
+
+@subheading The @code{-symbol-info-types} Command
+@findex -symbol-info-types
+@anchor{-symbol-info-types}

@subsubheading Synopsis

@smallexample
- -symbol-info-function
+ -symbol-info-types [--name @var{name_regexp}]
@end smallexample

-Show which function the symbol lives in.
+@noindent
+Returns a list of all defined types. The types are grouped by source
+file, and 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 options @code{--name} allows the list of types returned to be
+filtered by name.

@subsubheading @value{GDBN} Command

-@samp{gdb_get_function} in @code{gdbtk}.
+The corresponding @value{GDBN} command is @samp{info types}.

@subsubheading Example
-N.A.
+@smallexample
+(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",
+ definitions=[@{definition="float"@},
+ @{definition="int"@},
+ @{line="27",definition="typedef int my_int_t;"@}]@},
+ @{filename="gdb.mi/mi-sym-info-2.c",
+ fullname="/project/gdb.mi/mi-sym-info-2.c",
+ definitions=[@{line="24",definition="typedef float another_float_t;"@},
+ @{line="23",definition="typedef int another_int_t;"@},
+ @{definition="float"@},
+ @{definition="int"@}]@}]@}
+(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",
+ definitions=[@{line="27",definition="typedef int my_int_t;"@}]@},
+ @{filename="gdb.mi/mi-sym-info-2.c",
+ fullname="/project/gdb.mi/mi-sym-info-2.c",
+ definitions=[@{line="23",definition="typedef int another_int_t;"@}]@}]@}
+@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
+Returns a list containing the names and types for all global variables
+taken from the debug information. The variables are grouped by source
+file, and the line number on which each variable is definedd given.
+
+When @code{--include-nondebug} is passed then the output also includes
+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
+(gdb)
+-symbol-info-variables
+^done,symbols=
+ @{debug=
+ [@{filename="gdb.mi/mi-sym-info-1.c",
+ fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+ definitions=[@{line="25",definition="static float global_f1;"@},
+ @{line="24",definition="static int global_i1;"@}]@},
+ @{filename="gdb.mi/mi-sym-info-2.c",
+ fullname="/project/gdb.mi/mi-sym-info-2.c",
+ definitions=[@{line="21",definition="int global_f2;"@},
+ @{line="20",definition="int global_i2;"@},
+ @{line="19",definition="static float global_f1;"@},
+ @{line="18",definition="static int global_i1;"@}]@}]@}
+(gdb)
+-symbol-info-variables --name f1
+^done,symbols=
+ @{debug=
+ [@{filename="gdb.mi/mi-sym-info-1.c",
+ fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+ definitions=[@{line="25",definition="static float global_f1;"@}]@},
+ @{filename="gdb.mi/mi-sym-info-2.c",
+ fullname="/project/gdb.mi/mi-sym-info-2.c",
+ definitions=[@{line="19",definition="static float global_f1;"@}]@}]@}
+(gdb)
+-symbol-info-variables --type float
+^done,symbols=
+ @{debug=
+ [@{filename="gdb.mi/mi-sym-info-1.c",
+ fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+ definitions=[@{line="25",definition="static float global_f1;"@}]@},
+ @{filename="gdb.mi/mi-sym-info-2.c",
+ fullname="/project/gdb.mi/mi-sym-info-2.c",
+ definitions=[@{line="19",definition="static float global_f1;"@}]@}]@}
+(gdb)
+-symbol-info-variables --include-nondebug
+^done,symbols=
+ @{debug=
+ [@{filename="gdb.mi/mi-sym-info-1.c",
+ fullname="/project/gdb/testsuite/gdb.mi/mi-sym-info-1.c",
+ definitions=[@{line="25",definition="static float global_f1;"@},
+ @{line="24",definition="static int global_i1;"@}]@},
+ @{filename="gdb.mi/mi-sym-info-2.c",
+ fullname="/project/gdb.mi/mi-sym-info-2.c",
+ definitions=[@{line="21",definition="int global_f2;"@},
+ @{line="20",definition="int global_i2;"@},
+ @{line="19",definition="static float global_f1;"@},
+ @{line="18",definition="static int global_i1;"@}]@}],
+ nondebug=
+ [@{address="0x00000000004005d0",name="_IO_stdin_used"@},
+ @{address="0x00000000004005d8",name="__dso_handle"@}
+ ...
+ ]@}
+@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 37eab01de9e..df9f25fcbd0 100644
--- a/gdb/mi/mi-cmds.c
+++ b/gdb/mi/mi-cmds.c
@@ -151,6 +151,9 @@ static struct mi_cmd mi_cmds[] =
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 91ce4cd4070..5fa4fafbb05 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_locals;
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_variables;
+extern mi_cmd_argv_ftype mi_cmd_symbol_info_types;
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 63142e8e7e9..6c0cefcf88c 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,196 @@ mi_cmd_symbol_list_lines (const char *command, char **argv, int argc)
uiout->field_signed ("line", SYMTAB_LINETABLE (s)->item[i].line);
}
}
+
+/* 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. */
+
+static void
+mi_symbol_info (bool exclude_minsyms, const char *regexp,
+ enum search_domain kind, const char *t_regexp)
+{
+ struct ui_out *uiout = current_uiout;
+
+ /* Must make sure that if we're interrupted, symbols gets freed. */
+ std::vector<symbol_search> symbols = search_symbols (regexp, kind,
+ t_regexp, 0, NULL,
+ exclude_minsyms);
+
+ /* The outer container for all the matched symbols. */
+ ui_out_emit_tuple all_matching_symbols (uiout, "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> debug_func_emitter_outer;
+ gdb::optional<ui_out_emit_tuple> debug_func_emitter_symtab;
+ gdb::optional<ui_out_emit_list> debug_func_emitter_symbols;
+ gdb::optional<ui_out_emit_list> nondebug_func_emitter;
+
+ const symtab *last_symtab = nullptr;
+
+ for (const symbol_search &p : symbols)
+ {
+ QUIT;
+
+ if (p.msymbol.minsym != NULL)
+ {
+ if (debug_func_emitter_outer.has_value ())
+ {
+ gdb_assert (debug_func_emitter_symbols.has_value ());
+ gdb_assert (debug_func_emitter_symtab.has_value ());
+ debug_func_emitter_symbols.reset ();
+ debug_func_emitter_symtab.reset ();
+ debug_func_emitter_outer.reset ();
+ }
+
+ if (!nondebug_func_emitter.has_value ())
+ nondebug_func_emitter.emplace (uiout, "nondebug");
+ struct bound_minimal_symbol msymbol = p.msymbol;
+ struct gdbarch *gdbarch = get_objfile_arch (msymbol.objfile);
+ ui_out_emit_tuple tuple_emitter (uiout, NULL);
+ uiout->field_core_addr ("address", gdbarch,
+ BMSYMBOL_VALUE_ADDRESS (msymbol));
+ uiout->field_string ("name", MSYMBOL_PRINT_NAME (msymbol.minsym));
+ }
+ else
+ {
+ struct symbol *sym = p.symbol;
+ struct symtab *s = symbol_symtab (sym);
+
+ /* All debug symbols should appear in the list before all
+ non-debug symbols. */
+ gdb_assert (!nondebug_func_emitter.has_value ());
+
+ /* Start the list of debug symbols. */
+ if (!debug_func_emitter_outer.has_value ())
+ debug_func_emitter_outer.emplace (uiout, "debug");
+
+ if (s != last_symtab)
+ {
+ /* Reset a possible previous symbol list within a symtab. */
+ debug_func_emitter_symbols.reset ();
+ debug_func_emitter_symtab.reset ();
+
+ /* Start a new symtab and symbol list within the symtab. */
+ debug_func_emitter_symtab.emplace (uiout, nullptr);
+ uiout->field_string ("filename",
+ symtab_to_filename_for_display (s));
+ uiout->field_string ("fullname", symtab_to_fullname (s));
+ debug_func_emitter_symbols.emplace (uiout, "definitions");
+
+ /* Record the current symtab. */
+ last_symtab = s;
+ }
+
+ ui_out_emit_tuple tuple_emitter (uiout, NULL);
+ if (SYMBOL_LINE (sym) != 0)
+ uiout->field_unsigned ("line", SYMBOL_LINE (sym));
+ std::string str = symbol_to_info_string (sym, p.block, kind);
+ uiout->field_string ("definition", str.c_str ());
+ }
+ }
+}
+
+/* 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 (exclude_minsyms, regexp, kind, t_regexp);
+}
+
+/* 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-variables command. */
+void
+mi_cmd_symbol_info_variables (const char *command, char **argv, int argc)
+{
+ mi_info_functions_or_variables (VARIABLES_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 (true, regexp, TYPES_DOMAIN, nullptr);
+}
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 00000000000..9b6dc7396ad
--- /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 00000000000..c80877d8e7b
--- /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 00000000000..ce7216be7fa
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-sym-info.exp
@@ -0,0 +1,179 @@
+# 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\",definition=${qstr}\}"
+set type_re "\{(?:line=\"$decimal\",)*definition=${qstr}\}"
+set def_list "\\\[${fun_re}(?:,$fun_re)*\\\]"
+set type_def_list "\\\[${type_re}(?:,$type_re)*\\\]"
+set symtab_re \
+ "\{filename=${qstr},fullname=${qstr},definitions=${def_list}\}"
+set symtab_type_re \
+ "\{filename=${qstr},fullname=${qstr},definitions=${type_def_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" \
+ [join \
+ [list \
+ "116\\^done,symbols=\{debug=\\\[" \
+ "\{filename=\"\[^\"\]+${srcfile2}\"," \
+ "fullname=\"\[^\"\]+${srcfile2}\"," \
+ "definitions=\\\[" \
+ "\{line=\"${lineno}\"," \
+ "definition=\"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" \
+ [join \
+ [list \
+ "117\\^done,symbols=\{debug=\\\[" \
+ "\{filename=\"\[^\"\]+${srcfile}\"," \
+ "fullname=\"\[^\"\]+${srcfile}\"," \
+ "definitions=\\\[\{line=\"${lineno}\"," \
+ "definition=\"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" \
+ [join \
+ [list \
+ "118\\^done,symbols=\{debug=\\\[" \
+ "\{filename=\"\[^\"\]+${srcfile2}\"," \
+ "fullname=\"\[^\"\]+${srcfile2}\"," \
+ "definitions=\\\[" \
+ "\{line=\"${lineno}\"," \
+ "definition=\"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" \
+ [join \
+ [list \
+ "119\\^done,symbols=" \
+ "\{debug=\\\[" \
+ "\{filename=\"\[^\"\]+${srcfile}\"," \
+ "fullname=\"\[^\"\]+${srcfile}\"," \
+ "definitions=\\\[" \
+ "\{line=\"${lineno1}\"," \
+ "definition=\"static float global_f1;\"\}\\\]\}," \
+ "\{filename=\"\[^\"\]+${srcfile2}\"," \
+ "fullname=\"\[^\"\]+${srcfile2}\"," \
+ "definitions=\\\[" \
+ "\{line=\"${lineno2}\"," \
+ "definition=\"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_" \
+ [join \
+ [list \
+ "120\\^done,symbols=" \
+ "\{debug=\\\[" \
+ "\{filename=\"\[^\"\]+${srcfile}\"," \
+ "fullname=\"\[^\"\]+${srcfile}\"," \
+ "definitions=\\\[" \
+ "\{line=\"${lineno1}\"," \
+ "definition=\"typedef int my_int_t;\"\}\\\]\}," \
+ "\{filename=\"\[^\"\]+${srcfile2}\"," \
+ "fullname=\"\[^\"\]+${srcfile2}\"," \
+ "definitions=\\\[" \
+ "\{line=\"${lineno2}\"," \
+ "definition=\"typedef int another_int_t;\"\}" \
+ "\\\]\}\\\]\}"] "" ] \
+ "List all types matching _int_"
--
2.14.5