gdb/mi: add regexp filtering to -file-list-exec-source-files
authorAndrew Burgess <andrew.burgess@embecosm.com>
Tue, 18 May 2021 12:46:19 +0000 (13:46 +0100)
committerAndrew Burgess <andrew.burgess@embecosm.com>
Fri, 25 Jun 2021 19:54:29 +0000 (20:54 +0100)
This commit extends the existing MI command
-file-list-exec-source-files to provide the same regular expression
based filtering that the equivalent CLI command "info sources"
provides.

The new command syntax is:

  -file-list-exec-source-files [--basename | --dirname] [--] [REGEXP]

All options are optional, which ensures the command is backward
compatible.

As part of this work I have unified the CLI and MI code.

As a result of the unified code I now provide additional information
in the MI command output, there is now a new field 'debug-fully-read'
included with each source file.  This field which has the values
'true' or 'false', indicates if the source file is from a compilation
unit that has had its debug information fully read.  However, as this
is additional information, a well written front-end should just ignore
this field if it doesn't understand it, so things should still be
backward compatible.

gdb/ChangeLog:

* 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.

gdb/doc/ChangeLog:

* gdb.texinfo (GDB/MI File Commands): Document extensions to
-file-list-exec-source-files.

gdb/testsuite/ChangeLog:

* 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.

13 files changed:
gdb/ChangeLog
gdb/NEWS
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/mi/mi-cmd-file.c
gdb/symtab.c
gdb/symtab.h
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.dwarf2/dw2-filename.exp
gdb/testsuite/gdb.mi/mi-file.exp
gdb/testsuite/gdb.mi/mi-info-sources-base.c [new file with mode: 0644]
gdb/testsuite/gdb.mi/mi-info-sources.c [new file with mode: 0644]
gdb/testsuite/gdb.mi/mi-info-sources.exp [new file with mode: 0644]

index f4805f8efeeaf73eec1391b4722df183fc3712c4..aa1d458b2cfd9e2cfa2897b13caca07200d91872 100644 (file)
@@ -1,3 +1,30 @@
+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.
index aae3b49b40821f412326cd786670c2a34cc61c8c..8d79c50e1be3fde4f8caea67ef147a4c6eec94ed 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
     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
index fc16fc5f2a7d378c3447dc8110f5804309d2adea..4dc190407d4789ff92692fdef116c1799e49169d 100644 (file)
@@ -1,3 +1,8 @@
+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
index dfc00b120b42ae51219d999ea45c77c9f3adf6d1..1e56c3a882bac8e7d9b9eb2ef55a4eee859144d3 100644 (file)
@@ -35623,18 +35623,49 @@ The @value{GDBN} equivalent is @samp{info source}
 
 
 @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
 
@@ -35643,13 +35674,34 @@ The @value{GDBN} equivalent is @samp{info sources}.
 
 @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
index 430449c919e1d251f23bb38f59189b413dff4cab..684f7eb3f0c6703bc06da6107f3846ca7d297152 100644 (file)
@@ -62,54 +62,64 @@ mi_cmd_file_list_exec_source_file (const char *command, char **argv, int argc)
                       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.  */
index 2ff79e0cddfc544f8abc83db2c1152942c57b559..e300596be6ec5becdf1110cc574b07e485b8ee1c 100644 (file)
@@ -4200,58 +4200,6 @@ operator_chars (const char *p, const char **end)
 }
 \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,
@@ -4307,7 +4255,7 @@ info_sources_filter::matches (const char *fullname) const
 /* See class declaration.  */
 
 void
-info_sources_filter::print () const
+info_sources_filter::print (struct ui_out *uiout) const
 {
   if (m_c_regexp.has_value ())
     {
@@ -4316,12 +4264,12 @@ info_sources_filter::print () const
       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\")"),
@@ -4337,10 +4285,12 @@ info_sources_filter::print () const
 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);
@@ -4353,9 +4303,14 @@ struct 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.
@@ -4367,7 +4322,9 @@ struct output_source_filename_data
      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:
@@ -4380,12 +4337,17 @@ 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
@@ -4397,20 +4359,37 @@ output_source_filename_data::output (const char *name)
      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.  */
@@ -4418,9 +4397,9 @@ output_source_filename_data::output (const char *name)
 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
@@ -4476,6 +4455,42 @@ info_sources_command_completer (cmd_list_element *ignore,
     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
@@ -4493,7 +4508,7 @@ info_sources_command (const char *args, int from_tty)
     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)
@@ -4508,29 +4523,7 @@ info_sources_command (const char *args, int from_tty)
     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
@@ -6890,7 +6883,8 @@ Print information about all types matching REGEXP, or all types if no\n\
 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 (_("\
index a5d0168faf08f36418187fa2b8acec3256f62739..db0df5cb4bba28b9722f6aae404a7360bb5cfed5 100644 (file)
@@ -2385,4 +2385,67 @@ private:
   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) */
index 9bf8e9ebcc111e24dbbbaac1028e604d977be1ae..7eb13b82dfa67c4ae40f91b041c1d04759a6bf05 100644 (file)
@@ -1,3 +1,11 @@
+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
index 3e60f7d2bc9f42a4d215a518250e8bc7bf9a29f5..bd303c8547b21c4f66b6906e993e457246bbc987 100644 (file)
@@ -37,7 +37,7 @@ clean_restart ${testfile}
 # 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.*}
index 15d7d9f0944937bb0b91073f4a8d71c6b9245bfc..4cae33c017e92cf1201f6aab7cb25393a7331148 100644 (file)
@@ -68,7 +68,7 @@ proc test_file_list_exec_source_files {} {
 
     # 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."
 }
 
diff --git a/gdb/testsuite/gdb.mi/mi-info-sources-base.c b/gdb/testsuite/gdb.mi/mi-info-sources-base.c
new file mode 100644 (file)
index 0000000..cc73612
--- /dev/null
@@ -0,0 +1,23 @@
+/* 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;
+}
diff --git a/gdb/testsuite/gdb.mi/mi-info-sources.c b/gdb/testsuite/gdb.mi/mi-info-sources.c
new file mode 100644 (file)
index 0000000..b91b828
--- /dev/null
@@ -0,0 +1,25 @@
+/* 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;
+}
diff --git a/gdb/testsuite/gdb.mi/mi-info-sources.exp b/gdb/testsuite/gdb.mi/mi-info-sources.exp
new file mode 100644 (file)
index 0000000..c218af4
--- /dev/null
@@ -0,0 +1,147 @@
+# 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"