+2021-06-25 Andrew Burgess <andrew.burgess@embecosm.com>
+
+ * NEWS: Mention additions to -file-list-exec-source-files.
+ * mi/mi-cmd-file.c (print_partial_file_name): Delete.
+ (mi_cmd_file_list_exec_source_files): Rewrite to handle command
+ options, and make use of info_sources_worker.
+ * symtab.c (struct info_sources_filter): Moved to symtab.h.
+ (info_sources_filter::print): Take uiout argument, produce output
+ through uiout.
+ (struct output_source_filename_data)
+ <output_source_filename_data>: Take uiout argument, store into
+ m_uiout. <output>: Rewrite comment, add additional arguments to
+ declaration. <operator()>: Send more arguments to
+ output. <m_uiout>: New member variable.
+ (output_source_filename_data::output): Take extra arguments,
+ produce output through m_uiout, and structure for MI.
+ (output_source_filename_data::print_header): Produce output
+ through m_uiout.
+ (info_sources_worker): New function, the implementation is taken
+ from info_sources_command, but modified so produce output through
+ a ui_out.
+ (info_sources_command): The second half of this function has gone
+ to become info_sources_worker.
+ * symtab.h (struct info_sources_filter): Moved from symtab.c, add
+ extra parameter to print member function.
+ (info_sources_worker): Declare.
+
2021-06-25 Andrew Burgess <andrew.burgess@embecosm.com>
* symtab.c (struct info_sources_filter): New.
all locations of the selected breakpoint. This is equivalent to
the '-force' flag of the CLI's "cond" command.
+ ** '-file-list-exec-source-files [--basename | --dirname] [--] [REGEXP]'
+
+ The existing -file-list-exec-source-files command now takes an
+ optional REGEXP which is used to filter the source files that are
+ included in the results.
+
+ By default REGEXP is matched against the full filename of the
+ source file. When one of --basename or --dirname is given then
+ REGEXP is only matched against the specified part of the full
+ source filename.
+
+ The results from -file-list-exec-source-files now include a
+ 'debug-fully-read' field which takes the value 'true' or 'false'.
+ A 'true' value indicates the source file is from a compilation
+ unit that has had its debug information fully read in by GDB, a
+ value of 'false' indicates GDB has only performed a partial scan
+ of the debug information so far.
+
* GDB now supports core file debugging for x86_64 Cygwin programs.
* GDB will now look for the .gdbinit file in a config directory before
+2021-06-25 Andrew Burgess <andrew.burgess@embecosm.com>
+
+ * gdb.texinfo (GDB/MI File Commands): Document extensions to
+ -file-list-exec-source-files.
+
2021-06-25 Andrew Burgess <andrew.burgess@embecosm.com>
* python.texinfo (Breakpoints In Python): Add BP_CATCHPOINT
@subheading The @code{-file-list-exec-source-files} Command
+@kindex info sources
@findex -file-list-exec-source-files
@subsubheading Synopsis
@smallexample
- -file-list-exec-source-files
-@end smallexample
+ -file-list-exec-source-files @r{[} @var{--dirname} @r{|} @var{--basename} @r{]}
+ @r{[} -- @r{]}
+ @r{[} @var{regexp} @r{]}
+@end smallexample
+
+This command returns information about the source files @value{GDBN}
+knows about, it will output both the filename and fullname (absolute
+file name) of a source file, though the fullname can be elided if this
+information is not known to @value{GDBN}.
+
+With no arguments this command returns a list of source files. Each
+source file is represented by a tuple with the fields; @var{file},
+@var{fullname}, and @var{debug-fully-read}. The @var{file} is the
+display name for the file, while @var{fullname} is the absolute name
+of the file. The @var{fullname} field can be elided if the absolute
+name of the source file can't be computed. The field
+@var{debug-fully-read} will be a string, either @code{true} or
+@code{false}. When @code{true}, this indicates the full debug
+information for the compilation unit describing this file has been
+read in. When @code{false}, the full debug information has not yet
+been read in. While reading in the full debug information it is
+possible that @value{GDBN} could become aware of additional source
+files.
-List the source files for the current executable.
+The optional @var{regexp} can be used to filter the list of source
+files returned. The @var{regexp} will be matched against the full
+source file name. The matching is case-sensitive, except on operating
+systems that have case-insensitive filesystem (e.g.,
+MS-Windows). @samp{--} can be used before @var{regexp} to prevent
+@value{GDBN} interpreting @var{regexp} as a command option (e.g.@: if
+@var{regexp} starts with @samp{-}).
-It will always output both the filename and fullname (absolute file
-name) of a source file.
+If @code{--dirname} is provided, then @var{regexp} is matched only
+against the directory name of each source file. If @code{--basename}
+is provided, then @var{regexp} is matched against the basename of each
+source file. Only one of @code{--dirname} or @code{--basename} may be
+given, and if either is given then @var{regexp} is required.
@subsubheading @value{GDBN} Command
@subsubheading Example
@smallexample
-(gdb)
+(@value{GDBP})
-file-list-exec-source-files
-^done,files=[
-@{file=foo.c,fullname=/home/foo.c@},
-@{file=/home/bar.c,fullname=/home/bar.c@},
-@{file=gdb_could_not_find_fullpath.c@}]
-(gdb)
+^done,files=[@{file="foo.c",fullname="/home/foo.c",debug-fully-read="true"@},
+ @{file="/home/bar.c",fullname="/home/bar.c",debug-fully-read="true"@},
+ @{file="gdb_could_not_find_fullpath.c",debug-fully-read="true"@}]
+(@value{GDBP})
+-file-list-exec-source-files
+^done,files=[@{file="test.c",
+ fullname="/tmp/info-sources/test.c",
+ debug-fully-read="true"@},
+ @{file="/usr/include/stdc-predef.h",
+ fullname="/usr/include/stdc-predef.h",
+ debug-fully-read="true"@},
+ @{file="header.h",
+ fullname="/tmp/info-sources/header.h",
+ debug-fully-read="true"@},
+ @{file="helper.c",
+ fullname="/tmp/info-sources/helper.c",
+ debug-fully-read="true"@}]
+(@value{GDBP})
+-file-list-exec-source-files -- \\.c
+^done,files=[@{file="test.c",
+ fullname="/tmp/info-sources/test.c",
+ debug-fully-read="true"@},
+ @{file="helper.c",
+ fullname="/tmp/info-sources/helper.c",
+ debug-fully-read="true"@}]
+(@value{GDBP})
@end smallexample
@subheading The @code{-file-list-shared-libraries} Command
COMPUNIT_MACRO_TABLE (SYMTAB_COMPUNIT (st.symtab)) != NULL);
}
-/* A callback for map_partial_symbol_filenames. */
-
-static void
-print_partial_file_name (const char *filename, const char *fullname)
-{
- struct ui_out *uiout = current_uiout;
-
- uiout->begin (ui_out_type_tuple, NULL);
-
- uiout->field_string ("file", filename);
-
- if (fullname)
- uiout->field_string ("fullname", fullname);
-
- uiout->end (ui_out_type_tuple);
-}
+/* Implement -file-list-exec-source-files command. */
void
mi_cmd_file_list_exec_source_files (const char *command, char **argv, int argc)
{
- struct ui_out *uiout = current_uiout;
-
- if (!mi_valid_noargs ("-file-list-exec-source-files", argc, argv))
- error (_("-file-list-exec-source-files: Usage: No args"));
-
- /* Print the table header. */
- uiout->begin (ui_out_type_list, "files");
-
- /* Look at all of the file symtabs. */
- for (objfile *objfile : current_program_space->objfiles ())
+ enum opt
+ {
+ MATCH_BASENAME_OPT,
+ MATCH_DIRNAME_OPT
+ };
+ static const struct mi_opt opts[] =
+ {
+ {"-basename", MATCH_BASENAME_OPT, 0},
+ {"-dirname", MATCH_DIRNAME_OPT, 0},
+ { 0, 0, 0 }
+ };
+
+ /* Parse arguments. */
+ int oind = 0;
+ char *oarg;
+
+ bool match_on_basename = false;
+ bool match_on_dirname = false;
+
+ while (1)
{
- for (compunit_symtab *cu : objfile->compunits ())
+ int opt = mi_getopt ("-file-list-exec-source-files", argc, argv,
+ opts, &oind, &oarg);
+ if (opt < 0)
+ break;
+ switch ((enum opt) opt)
{
- for (symtab *s : compunit_filetabs (cu))
- {
- uiout->begin (ui_out_type_tuple, NULL);
-
- uiout->field_string ("file", symtab_to_filename_for_display (s));
- uiout->field_string ("fullname", symtab_to_fullname (s));
-
- uiout->end (ui_out_type_tuple);
- }
+ case MATCH_BASENAME_OPT:
+ match_on_basename = true;
+ break;
+ case MATCH_DIRNAME_OPT:
+ match_on_dirname = true;
+ break;
}
}
- map_symbol_filenames (print_partial_file_name, true /*need_fullname*/);
+ if ((argc - oind > 1) || (match_on_basename && match_on_dirname))
+ error (_("-file-list-exec-source-files: Usage: [--basename | --dirname] [--] REGEXP"));
+
+ const char *regexp = nullptr;
+ if (argc - oind == 1)
+ regexp = argv[oind];
+
+ info_sources_filter::match_on match_type;
+ if (match_on_dirname)
+ match_type = info_sources_filter::match_on::DIRNAME;
+ else if (match_on_basename)
+ match_type = info_sources_filter::match_on::BASENAME;
+ else
+ match_type = info_sources_filter::match_on::FULLNAME;
- uiout->end (ui_out_type_list);
+ info_sources_filter filter (match_type, regexp);
+ info_sources_worker (current_uiout, filter);
}
/* See mi-cmds.h. */
}
\f
-/* Class used to encapsulate the filename filtering for the "info sources"
- command. */
-struct info_sources_filter
-{
- /* If filename filtering is being used (see M_C_REGEXP) then which part
- of the filename is being filtered against? */
- enum class match_on
- {
- /* Match against the full filename. */
- FULLNAME,
-
- /* Match only against the directory part of the full filename. */
- DIRNAME,
-
- /* Match only against the basename part of the full filename. */
- BASENAME
- };
-
- /* Create a filter of MATCH_TYPE using regular expression REGEXP. If
- REGEXP is nullptr then all files will match the filter and MATCH_TYPE
- is ignored.
-
- The string pointed too by REGEXP must remain live and unchanged for
- this lifetime of this object as the object only retains a copy of the
- pointer. */
- info_sources_filter (match_on match_type, const char *regexp);
-
- DISABLE_COPY_AND_ASSIGN (info_sources_filter);
-
- /* Does FULLNAME match the filter defined by this object, return true if
- it does, otherwise, return false. If there is no filtering defined
- then this function will always return true. */
- bool matches (const char *fullname) const;
-
- /* Print a single line describing this filter, used as part of the "info
- sources" command output. If there is no filter in place then nothing
- is printed. */
- void print () const;
-
-private:
-
- /* The type of filtering in place. */
- match_on m_match_type;
-
- /* Points to the original regexp used to create this filter. */
- const char *m_regexp;
-
- /* A compiled version of M_REGEXP. This object is only given a value if
- M_REGEXP is not nullptr and is not the empty string. */
- gdb::optional<compiled_regex> m_c_regexp;
-};
-
/* See class declaration. */
info_sources_filter::info_sources_filter (match_on match_type,
/* See class declaration. */
void
-info_sources_filter::print () const
+info_sources_filter::print (struct ui_out *uiout) const
{
if (m_c_regexp.has_value ())
{
switch (m_match_type)
{
case match_on::DIRNAME:
- printf_filtered (_("(dirname matching regular expression \"%s\")"),
- m_regexp);
+ uiout->message (_("(dirname matching regular expression \"%s\")"),
+ m_regexp);
break;
case match_on::BASENAME:
- printf_filtered (_("(basename matching regular expression \"%s\")"),
- m_regexp);
+ uiout->message (_("(basename matching regular expression \"%s\")"),
+ m_regexp);
break;
case match_on::FULLNAME:
printf_filtered (_("(filename matching regular expression \"%s\")"),
struct output_source_filename_data
{
/* Create an object for displaying the results of the 'info sources'
- command. FILTER must remain valid and unchanged for the lifetime of
- this object as this object retains a reference to FILTER. */
- output_source_filename_data (const info_sources_filter &filter)
- : m_filter (filter)
+ command to UIOUT. FILTER must remain valid and unchanged for the
+ lifetime of this object as this object retains a reference to FILTER. */
+ output_source_filename_data (struct ui_out *uiout,
+ const info_sources_filter &filter)
+ : m_filter (filter),
+ m_uiout (uiout)
{ /* Nothing. */ }
DISABLE_COPY_AND_ASSIGN (output_source_filename_data);
m_filename_seen_cache.clear ();
}
- /* Worker for sources_info. Force line breaks at ,'s. NAME is the name
- to print. */
- void output (const char *name);
+ /* Worker for sources_info, outputs the file name formatted for either
+ cli or mi (based on the current_uiout). In cli mode displays
+ FULLNAME with a comma separating this name from any previously
+ printed name (line breaks are added at the comma). In MI mode
+ outputs a tuple containing DISP_NAME (the files display name),
+ FULLNAME, and EXPANDED_P (true when this file is from a fully
+ expanded symtab, otherwise false). */
+ void output (const char *disp_name, const char *fullname, bool expanded_p);
/* Prints the header messages for the source files that will be printed
with the matching info present in the current object state.
quick_symbol_functions::map_symbol_filenames. */
void operator() (const char *filename, const char *fullname)
{
- output (fullname != nullptr ? fullname : filename);
+ /* The false here indicates that this file is from an unexpanded
+ symtab. */
+ output (filename, fullname, false);
}
private:
/* How source filename should be filtered. */
const info_sources_filter &m_filter;
+
+ /* The object to which output is sent. */
+ struct ui_out *m_uiout;
};
/* See comment in class declaration above. */
void
-output_source_filename_data::output (const char *name)
+output_source_filename_data::output (const char *disp_name,
+ const char *fullname,
+ bool expanded_p)
{
/* Since a single source file can result in several partial symbol
tables, we need to avoid printing it more than once. Note: if
symtabs; it doesn't hurt to check. */
/* Was NAME already seen? If so, then don't print it again. */
- if (m_filename_seen_cache.seen (name))
+ if (m_filename_seen_cache.seen (fullname))
return;
/* If the filter rejects this file then don't print it. */
- if (!m_filter.matches (name))
+ if (!m_filter.matches (fullname))
return;
+ ui_out_emit_tuple ui_emitter (m_uiout, nullptr);
+
/* Print it and reset *FIRST. */
if (!m_first)
- printf_filtered (", ");
+ m_uiout->text (", ");
m_first = false;
wrap_here ("");
- fputs_styled (name, file_name_style.style (), gdb_stdout);
+ if (m_uiout->is_mi_like_p ())
+ {
+ m_uiout->field_string ("file", disp_name, file_name_style.style ());
+ if (fullname != nullptr)
+ m_uiout->field_string ("fullname", fullname,
+ file_name_style.style ());
+ m_uiout->field_string ("debug-fully-read",
+ (expanded_p ? "true" : "false"));
+ }
+ else
+ {
+ if (fullname == nullptr)
+ fullname = disp_name;
+ m_uiout->field_string ("fullname", fullname,
+ file_name_style.style ());
+ }
}
/* See comment is class declaration above. */
void
output_source_filename_data::print_header (const char *symbol_msg)
{
- puts_filtered (symbol_msg);
- m_filter.print ();
- puts_filtered ("\n");
+ m_uiout->text (symbol_msg);
+ m_filter.print (m_uiout);
+ m_uiout->text ("\n");
}
/* For the 'info sources' command, what part of the file names should we be
return;
}
+/* See symtab.h. */
+
+void
+info_sources_worker (struct ui_out *uiout,
+ const info_sources_filter &filter)
+{
+ output_source_filename_data data (uiout, filter);
+
+ ui_out_emit_list results_emitter (uiout, "files");
+ gdb::optional<ui_out_emit_tuple> output_tuple;
+ gdb::optional<ui_out_emit_list> sources_list;
+
+ if (!uiout->is_mi_like_p ())
+ data.print_header (_("Source files for which symbols have been read in:\n"));
+
+ for (objfile *objfile : current_program_space->objfiles ())
+ {
+ for (compunit_symtab *cu : objfile->compunits ())
+ {
+ for (symtab *s : compunit_filetabs (cu))
+ {
+ const char *file = symtab_to_filename_for_display (s);
+ const char *fullname = symtab_to_fullname (s);
+ data.output (file, fullname, true);
+ }
+ }
+ }
+
+ uiout->text ("\n\n");
+ if (!uiout->is_mi_like_p ())
+ data.print_header (_("Source files for which symbols will be read in on demand:\n"));
+ data.reset_output ();
+ map_symbol_filenames (data, true /*need_fullname*/);
+ uiout->text ("\n");
+}
+
/* Implement the 'info sources' command. */
static void
error (_("You cannot give both -basename and -dirname to 'info sources'."));
const char *regex = nullptr;
- if (args != nullptr && *args != '\000')
+ if (args != NULL && *args != '\000')
regex = args;
if ((match_opts.dirname || match_opts.basename) && regex == nullptr)
match_type = info_sources_filter::match_on::FULLNAME;
info_sources_filter filter (match_type, regex);
- output_source_filename_data data (filter);
-
- data.print_header (_("Source files for which symbols have been read in:\n"));
-
- for (objfile *objfile : current_program_space->objfiles ())
- {
- for (compunit_symtab *cu : objfile->compunits ())
- {
- for (symtab *s : compunit_filetabs (cu))
- {
- const char *fullname = symtab_to_fullname (s);
-
- data.output (fullname);
- }
- }
- }
- printf_filtered ("\n\n");
-
- data.print_header (_("Source files for which symbols will be read in on demand:\n"));
-
- data.reset_output ();
- map_symbol_filenames (data, true /*need_fullname*/);
- printf_filtered ("\n");
+ info_sources_worker (current_uiout, filter);
}
/* Compare FILE against all the entries of FILENAMES. If BASENAMES is
REGEXP is given. The optional flag -q disables printing of headers."));
set_cmd_completer_handle_brkchars (c, info_types_command_completer);
- const auto info_sources_opts = make_info_sources_options_def_group (nullptr);
+ const auto info_sources_opts
+ = make_info_sources_options_def_group (nullptr);
static std::string info_sources_help
= gdb::option::build_help (_("\
std::vector<bound_minimal_symbol> m_minimal_symbols;
};
+/* Class used to encapsulate the filename filtering for the "info sources"
+ command. */
+
+struct info_sources_filter
+{
+ /* If filename filtering is being used (see M_C_REGEXP) then which part
+ of the filename is being filtered against? */
+ enum class match_on
+ {
+ /* Match against the full filename. */
+ FULLNAME,
+
+ /* Match only against the directory part of the full filename. */
+ DIRNAME,
+
+ /* Match only against the basename part of the full filename. */
+ BASENAME
+ };
+
+ /* Create a filter of MATCH_TYPE using regular expression REGEXP. If
+ REGEXP is nullptr then all files will match the filter and MATCH_TYPE
+ is ignored.
+
+ The string pointed too by REGEXP must remain live and unchanged for
+ this lifetime of this object as the object only retains a copy of the
+ pointer. */
+ info_sources_filter (match_on match_type, const char *regexp);
+
+ DISABLE_COPY_AND_ASSIGN (info_sources_filter);
+
+ /* Does FULLNAME match the filter defined by this object, return true if
+ it does, otherwise, return false. If there is no filtering defined
+ then this function will always return true. */
+ bool matches (const char *fullname) const;
+
+ /* Print a single line describing this filter to UIOUT, used as part of
+ the "info sources" command output. If there is no filter in place
+ then nothing is printed. */
+ void print (struct ui_out *uiout) const;
+
+private:
+
+ /* The type of filtering in place. */
+ match_on m_match_type;
+
+ /* Points to the original regexp used to create this filter. */
+ const char *m_regexp;
+
+ /* A compiled version of M_REGEXP. This object is only given a value if
+ M_REGEXP is not nullptr and is not the empty string. */
+ gdb::optional<compiled_regex> m_c_regexp;
+};
+
+/* Perform the core of the 'info sources' command.
+
+ FILTER is used to perform regular expression based filtering on the
+ source files that will be displayed.
+
+ Output is written to UIOUT in CLI or MI style as appropriate. */
+
+extern void info_sources_worker (struct ui_out *uiout,
+ const info_sources_filter &filter);
+
#endif /* !defined(SYMTAB_H) */
+2021-06-25 Andrew Burgess <andrew.burgess@embecosm.com>
+
+ * gdb.dwarf2/dw2-filename.exp: Update expected results.
+ * gdb.mi/mi-file.exp: Likewise.
+ * gdb.mi/mi-info-sources-base.c: New file.
+ * gdb.mi/mi-info-sources.c: New file.
+ * gdb.mi/mi-info-sources.exp: New file.
+
2021-06-25 Andrew Burgess <andrew.burgess@embecosm.com>
* gdb.cp/method-call-in-c.cc (struct foo_type): Add static member
# the full path to that file. What we want to verify, most of all,
# is that the file and fullname fields are now inverted.
gdb_test "interpreter-exec mi -file-list-exec-source-files" \
- ".*{file=\"file1\\.txt\",fullname=\".+file1\\.txt\"}.*"
+ ".*{file=\"file1\\.txt\",fullname=\".+file1\\.txt\",debug-fully-read=\"\[^\"\]+\"}.*"
# And `info sources' should return the fullname incl. the directories.
gdb_test "info sources" {[/]file1\.txt.*}
# get the path and absolute path to the current executable
mi_gdb_test "222-file-list-exec-source-files" \
- "222\\\^done,files=\\\[\{file=\".*${srcfile}\",fullname=\"$fullname_syntax${srcfile}\"\}.*]" \
+ "222\\\^done,files=\\\[\{file=\".*${srcfile}\",fullname=\"$fullname_syntax${srcfile}\",debug-fully-read=\"\[^\"\]+\"\}.*]" \
"Getting a list of source files."
}
--- /dev/null
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2019-2021 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/>. */
+
+/* This file was originally copied from gdb.base/info_sources_base.c. */
+
+void some_other_func (void)
+{
+ return;
+}
--- /dev/null
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2019-2021 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/>. */
+
+/* This file was originally copied from gdb.base/info_sources.c. */
+
+extern void some_other_func (void);
+int main ()
+{
+ some_other_func ();
+ return 0;
+}
--- /dev/null
+# Copyright 2021 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 the -file-list-exec-source-files command.
+
+load_lib mi-support.exp
+set MIFLAGS "-i=mi"
+
+standard_testfile .c -base.c
+
+if {[prepare_for_testing $testfile.exp $testfile \
+ [list $srcfile $srcfile2] debug]} {
+ untested $testfile.exp
+ return -1
+}
+
+mi_clean_restart $binfile
+
+mi_runto_main
+
+# Helper to build expected MI output pattern for a list. NAME is the
+# name of the list (which can be the empty string) and args is one
+# or more strings representing the fields of the list, which will be
+# joined with a comma.
+#
+# If any of the fields in args matches ".*" then the comma before and
+# after are dropped from the final pattern.
+proc mi_list { name args } {
+ set str ""
+
+ if { $name != "" } {
+ set str "${name}="
+ }
+
+ set pattern ""
+ foreach a $args {
+ if { [string length $pattern] > 0 } {
+ if { [string range $pattern end-1 end] != ".*" \
+ && [string range $a 0 1] != ".*" } {
+ set pattern "${pattern},"
+ }
+ }
+ set pattern "${pattern}${a}"
+ }
+ set str "$str\\\[${pattern}\\\]"
+ return ${str}
+}
+
+# Helper to build expected MI output pattern for a tuple. NAME is the
+# name of the tuple (which can be the empty string) and args is one
+# or more strings representing the fields of the tuple, which will be
+# joined with a comma.
+#
+# If any of the fields in args matches ".*" then the comma before and
+# after are dropped from the final pattern.
+proc mi_tuple { name args } {
+ set str ""
+
+ if { $name != "" } {
+ set str "${name}="
+ }
+
+ set pattern ""
+ foreach a $args {
+ if { [string length $pattern] > 0 } {
+ if { [string range $pattern end-1 end] != ".*" \
+ && [string range $a 0 1] != ".*" } {
+ set pattern "${pattern},"
+ }
+ }
+ set pattern "${pattern}${a}"
+ }
+ set str "$str\\{${pattern}\\}"
+ return ${str}
+}
+
+# Helper to build expected MI output pattern for a single field. NAME
+# is the name of the field, and PATTERN matches the fields contents.
+# This proc will add quotes around PATTERN.
+proc mi_field { name pattern } {
+ set str ""
+
+ if { $name != "" } {
+ set str "${name}="
+ }
+
+ set str "$str\"${pattern}\""
+ return ${str}
+}
+
+# Run tests on '-file-list-exec-source-files'. DEBUG_FULLY_READ is either the string
+# "true" or "false" and indicates if the GDB will have read all the
+# debug for the test program or not yet.
+proc check_info_sources { debug_fully_read } {
+
+ with_test_prefix "debug_read=${debug_fully_read}" {
+
+ if { $debug_fully_read } {
+ set p [mi_list "files" \
+ [mi_tuple "" \
+ [mi_field "file" "\[^\"\]+/mi-info-sources-base\\.c"] \
+ [mi_field "fullname" "\[^\"\]+/mi-info-sources-base\\.c"] \
+ [mi_field "debug-fully-read" "${debug_fully_read}"]] \
+ [mi_tuple "" \
+ [mi_field "file" "\[^\"\]+/mi-info-sources\\.c"] \
+ [mi_field "fullname" "\[^\"\]+/mi-info-sources\\.c"] \
+ [mi_field "debug-fully-read" "true"]]]
+ } else {
+ set p [mi_list "files" \
+ [mi_tuple "" \
+ [mi_field "file" "\[^\"\]+/mi-info-sources\\.c"] \
+ [mi_field "fullname" "\[^\"\]+/mi-info-sources\\.c"] \
+ [mi_field "debug-fully-read" "true"]] \
+ [mi_tuple "" \
+ [mi_field "file" "\[^\"\]+/mi-info-sources-base\\.c"] \
+ [mi_field "fullname" "\[^\"\]+/mi-info-sources-base\\.c"] \
+ [mi_field "debug-fully-read" "${debug_fully_read}"]]]
+ }
+ mi_gdb_test "-file-list-exec-source-files" ".*\\^done,${p}" "-file-list-exec-source-files"
+
+ set p [mi_list "files" \
+ [mi_tuple "" \
+ [mi_field "file" "\[^\"\]+/mi-info-sources-base\\.c"] \
+ [mi_field "fullname" "\[^\"\]+/mi-info-sources-base\\.c"] \
+ [mi_field "debug-fully-read" "${debug_fully_read}"]]]
+ mi_gdb_test "-file-list-exec-source-files --basename -- base" ".*\\^done,${p}" \
+ "-file-list-exec-source-files --basename -- base"
+ }
+}
+
+check_info_sources "false"
+
+mi_continue_to "some_other_func"
+
+check_info_sources "true"