public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/4] New option for 'info sources', also better MI support
@ 2021-04-26 17:06 Andrew Burgess
  2021-04-26 17:07 ` [PATCH 1/4] gdb: add new function quick_symbol_functions::has_unexpanded_symbols Andrew Burgess
                   ` (5 more replies)
  0 siblings, 6 replies; 38+ messages in thread
From: Andrew Burgess @ 2021-04-26 17:06 UTC (permalink / raw)
  To: gdb-patches

Patches #1 and #2 are setup/cleanup, then...

patch #2 adds a new option to 'info sources' to get a different view
on the data, and...

patch #3 extends the existing MI equivalent of 'info sources' making
it as powerful as the CLI version.

---

Andrew Burgess (4):
  gdb: add new function quick_symbol_functions::has_unexpanded_symbols
  gdb: make struct output_source_filename_data more C++ like
  gdb: add new -group-by-binary flag to info sources command
  gdb/mi: extend -file-list-exec-source-files command

 gdb/ChangeLog                                 |  79 ++++
 gdb/NEWS                                      |  18 +
 gdb/doc/ChangeLog                             |  10 +
 gdb/doc/gdb.texinfo                           | 159 ++++++--
 gdb/dwarf2/read.c                             |  22 ++
 gdb/mi/mi-cmd-file.c                          |  84 ++--
 gdb/objfiles.h                                |   6 +
 gdb/psympriv.h                                |   2 +
 gdb/psymtab.c                                 |  18 +
 gdb/quick-symbol.h                            |   6 +
 gdb/symfile-debug.c                           |  13 +
 gdb/symtab.c                                  | 361 ++++++++++++------
 gdb/symtab.h                                  |  24 ++
 gdb/testsuite/ChangeLog                       |  16 +
 gdb/testsuite/gdb.base/info_sources.exp       |   5 +
 .../gdb.base/info_sources_2-header.h          |  28 ++
 gdb/testsuite/gdb.base/info_sources_2-lib.c   |  25 ++
 gdb/testsuite/gdb.base/info_sources_2-test.c  |  26 ++
 gdb/testsuite/gdb.base/info_sources_2.exp     | 169 ++++++++
 gdb/testsuite/gdb.dwarf2/dw2-filename.exp     |   2 +-
 gdb/testsuite/gdb.mi/mi-file.exp              |   2 +-
 gdb/testsuite/gdb.mi/mi-info-sources-base.c   |  24 ++
 gdb/testsuite/gdb.mi/mi-info-sources.c        |  25 ++
 gdb/testsuite/gdb.mi/mi-info-sources.exp      | 177 +++++++++
 24 files changed, 1127 insertions(+), 174 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/info_sources_2-header.h
 create mode 100644 gdb/testsuite/gdb.base/info_sources_2-lib.c
 create mode 100644 gdb/testsuite/gdb.base/info_sources_2-test.c
 create mode 100644 gdb/testsuite/gdb.base/info_sources_2.exp
 create mode 100644 gdb/testsuite/gdb.mi/mi-info-sources-base.c
 create mode 100644 gdb/testsuite/gdb.mi/mi-info-sources.c
 create mode 100644 gdb/testsuite/gdb.mi/mi-info-sources.exp

-- 
2.25.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 1/4] gdb: add new function quick_symbol_functions::has_unexpanded_symbols
  2021-04-26 17:06 [PATCH 0/4] New option for 'info sources', also better MI support Andrew Burgess
@ 2021-04-26 17:07 ` Andrew Burgess
  2021-05-13 14:38   ` Simon Marchi
  2021-05-13 14:46   ` Simon Marchi
  2021-04-26 17:07 ` [PATCH 2/4] gdb: make struct output_source_filename_data more C++ like Andrew Burgess
                   ` (4 subsequent siblings)
  5 siblings, 2 replies; 38+ messages in thread
From: Andrew Burgess @ 2021-04-26 17:07 UTC (permalink / raw)
  To: gdb-patches

Adds a new function to the quick_symbol_functions API to let us know
if there are any unexpanded symbols.  This functionality is required
by a later commit.  After this commit the functionality is unused, and
untested.

There should be no user visible changes after this commit.

gdb/ChangeLog:

	* dwarf2/read.c (struct dwarf2_base_index_functions)
	<has_unexpanded_symbols>: Declare.
	(dwarf2_base_index_functions::has_unexpanded_symbols): Define new
	function.
	* objfiles.h (struct objfile) <has_unexpanded_symbols>: Declare.
	* psympriv.h (struct psymbol_functions) <has_unexpanded_symbols>:
	Declare.
	* psymtab.c (psymbol_functions::has_unexpanded_symbols): Define
	new function.
	* quick-symbol.h (struct quick_symbol_functions)
	<has_unexpanded_symbols>: Declare.
	* symfile-debug.c (objfile::has_unexpanded_symbols): Define new
	function.
---
 gdb/ChangeLog       | 16 ++++++++++++++++
 gdb/dwarf2/read.c   | 22 ++++++++++++++++++++++
 gdb/objfiles.h      |  6 ++++++
 gdb/psympriv.h      |  2 ++
 gdb/psymtab.c       | 18 ++++++++++++++++++
 gdb/quick-symbol.h  |  6 ++++++
 gdb/symfile-debug.c | 13 +++++++++++++
 7 files changed, 83 insertions(+)

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 306971ef1b7..5ab0c59c7ae 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -2275,6 +2275,8 @@ struct dwarf2_base_index_functions : public quick_symbol_functions
 {
   bool has_symbols (struct objfile *objfile) override;
 
+  bool has_unexpanded_symbols (struct objfile *objfile) override;
+
   struct symtab *find_last_source_symtab (struct objfile *objfile) override;
 
   void forget_cached_source_info (struct objfile *objfile) override;
@@ -4767,6 +4769,26 @@ dwarf2_base_index_functions::has_symbols (struct objfile *objfile)
   return true;
 }
 
+/* See quick_symbol_functions::has_unexpanded_symbols in quick-symbol.h.  */
+
+bool
+dwarf2_base_index_functions::has_unexpanded_symbols (struct objfile *objfile)
+{
+  dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile);
+
+  for (dwarf2_per_cu_data *per_cu : per_objfile->per_bfd->all_comp_units)
+    {
+      /* Is this already expanded?  */
+      if (per_objfile->symtab_set_p (per_cu))
+	continue;
+
+      /* It has not yet been expanded.  */
+      return true;
+    }
+
+  return false;
+}
+
 /* DWARF-5 debug_names reader.  */
 
 /* DWARF-5 augmentation string for GDB's DW_IDX_GNU_* extension.  */
diff --git a/gdb/objfiles.h b/gdb/objfiles.h
index 5a8a782a646..72d9bab5555 100644
--- a/gdb/objfiles.h
+++ b/gdb/objfiles.h
@@ -565,6 +565,12 @@ struct objfile
 
   bool has_partial_symbols ();
 
+  /* Return true if this objfile has any unexpanded symbols.  A return
+     value of false indicates either, that this objfile has all its
+     symbols fully expanded (i.e. fully read in), or that this objfile has
+     no symbols at all (i.e. no debug information).  */
+  bool has_unexpanded_symbols ();
+
   /* See quick_symbol_functions.  */
   struct symtab *find_last_source_symtab ();
 
diff --git a/gdb/psympriv.h b/gdb/psympriv.h
index 59dd66f57e5..1712ad978e6 100644
--- a/gdb/psympriv.h
+++ b/gdb/psympriv.h
@@ -503,6 +503,8 @@ struct psymbol_functions : public quick_symbol_functions
 
   bool has_symbols (struct objfile *objfile) override;
 
+  bool has_unexpanded_symbols (struct objfile *objfile) override;
+
   struct symtab *find_last_source_symtab (struct objfile *objfile) override;
 
   void forget_cached_source_info (struct objfile *objfile) override;
diff --git a/gdb/psymtab.c b/gdb/psymtab.c
index 75a307c89aa..cc5eb503902 100644
--- a/gdb/psymtab.c
+++ b/gdb/psymtab.c
@@ -1185,6 +1185,24 @@ psymbol_functions::has_symbols (struct objfile *objfile)
   return m_partial_symtabs->psymtabs != NULL;
 }
 
+/* See quick_symbol_functions::has_unexpanded_symbols in quick-symbol.h.  */
+
+bool
+psymbol_functions::has_unexpanded_symbols (struct objfile *objfile)
+{
+  for (partial_symtab *psymtab : require_partial_symbols (objfile))
+    {
+      /* Is this already expanded?  */
+      if (psymtab->readin_p (objfile))
+	continue;
+
+      /* It has not yet been expanded.  */
+      return true;
+    }
+
+  return false;
+}
+
 /* Helper function for psym_find_compunit_symtab_by_address that fills
    in m_psymbol_map for a given range of psymbols.  */
 
diff --git a/gdb/quick-symbol.h b/gdb/quick-symbol.h
index f06ceff41c2..096053e75e9 100644
--- a/gdb/quick-symbol.h
+++ b/gdb/quick-symbol.h
@@ -86,6 +86,12 @@ struct quick_symbol_functions
      available.  */
   virtual bool has_symbols (struct objfile *objfile) = 0;
 
+  /* Return true if OBJFILE has any unexpanded symbols.  A return value of
+     false indicates there are no unexpanded symbols, this might mean that
+     all of the symbols have been expanded (full debug has been read in),
+     or it might been that OBJFILE has no debug information.  */
+  virtual bool has_unexpanded_symbols (struct objfile *objfile) = 0;
+
   /* Return the symbol table for the "last" file appearing in
      OBJFILE.  */
   virtual struct symtab *find_last_source_symtab (struct objfile *objfile) = 0;
diff --git a/gdb/symfile-debug.c b/gdb/symfile-debug.c
index b839194e2f7..cfc3bed9222 100644
--- a/gdb/symfile-debug.c
+++ b/gdb/symfile-debug.c
@@ -100,6 +100,19 @@ objfile::has_partial_symbols ()
   return retval;
 }
 
+/* See objfiles.h.  */
+bool
+objfile::has_unexpanded_symbols ()
+{
+  for (const auto &iter : qf)
+    {
+      if (iter->has_unexpanded_symbols (this))
+	return true;
+    }
+
+  return false;
+}
+
 struct symtab *
 objfile::find_last_source_symtab ()
 {
-- 
2.25.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 2/4] gdb: make struct output_source_filename_data more C++ like
  2021-04-26 17:06 [PATCH 0/4] New option for 'info sources', also better MI support Andrew Burgess
  2021-04-26 17:07 ` [PATCH 1/4] gdb: add new function quick_symbol_functions::has_unexpanded_symbols Andrew Burgess
@ 2021-04-26 17:07 ` Andrew Burgess
  2021-05-13 14:58   ` Simon Marchi
  2021-04-26 17:07 ` [PATCH 3/4] gdb: add new -group-by-binary flag to info sources command Andrew Burgess
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 38+ messages in thread
From: Andrew Burgess @ 2021-04-26 17:07 UTC (permalink / raw)
  To: gdb-patches

In a future commit I'm going to be making some changes to the 'info
sources' command.  While looking at the code I noticed that things
could be improved by making struct output_source_filename_data more
C++ like (private member variables, and more member functions).
That's what this commit does.

The change to make filename_partial_match_opts private within
output_source_filename_data might seem unhelpful (we now have to
create a stack local variable and initialise this field through the
constructor), however, in a later commit I plan to split the function
info_sources_command in two, and having output_source_filename_data
initialised entirely through the constructor will make this process
easier.

There should be no user visible changes after this commit.

gdb/ChangeLog:

	* symtab.c (struct filename_partial_match_opts): Update comment.
	(struct output_source_filename_data)
	<output_source_filename_data>: New constructor.  <regexp>: Rename
	to m_regexp.  <c_regexp>: Rename to m_c_regexp.  <reset_output>:
	New member function.  <filename_seen_cache>: Rename to
	m_filename_seen_cache, change from being a pointer, to being an
	actual object.  <set_regexp>: New member function.  <first>:
	Rename to m_first.  <print_header>: New member
	function. <partial_match>: Renamed to m_partial_match.
	(output_source_filename_data::output): Update now
	m_filename_seen_cache is no longer a pointer, and for other member
	variable name changes. Add a header comment.
	(print_info_sources_header): Renamed to...
	(output_source_filename_data::print_header): ...this.  Update now
	it's a member function and to take account of member variable
	renaming.
	(info_sources_command): Add a header comment, delete stack local
	filename_seen_cache, initialization of output_source_filename_data
	is now done by the constructor.  Call print_header member function
	instead of print_info_sources_header, call reset_output member
	function instead of manually performing the reset.
---
 gdb/ChangeLog |  24 +++++++
 gdb/symtab.c  | 183 +++++++++++++++++++++++++++++---------------------
 2 files changed, 129 insertions(+), 78 deletions(-)

diff --git a/gdb/symtab.c b/gdb/symtab.c
index 061177e1d23..5650d225752 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4200,7 +4200,8 @@ operator_chars (const char *p, const char **end)
 }
 \f
 
-/* What part to match in a file name.  */
+/* For the 'info sources' command, what part of the file names should we be
+   matching the user supplied regular expression against?  */
 
 struct filename_partial_match_opts
 {
@@ -4211,35 +4212,83 @@ struct filename_partial_match_opts
   bool basename = false;
 };
 
-/* Data structure to maintain printing state for output_source_filename.  */
+/* Data structure to maintain the state used for printing the results of
+   the 'info sources' command.  */
 
 struct output_source_filename_data
 {
-  /* Output only filenames matching REGEXP.  */
-  std::string regexp;
-  gdb::optional<compiled_regex> c_regexp;
-  /* Possibly only match a part of the filename.  */
-  filename_partial_match_opts partial_match;
+  output_source_filename_data (const char *regexp,
+			       bool match_on_dirname,
+			       bool match_on_basename)
+  {
+    m_partial_match.dirname = match_on_dirname;
+    m_partial_match.basename = match_on_basename;
 
+    if (regexp != nullptr)
+      set_regexp (regexp);
+  }
 
-  /* Cache of what we've seen so far.  */
-  struct filename_seen_cache *filename_seen_cache;
+  DISABLE_COPY_AND_ASSIGN (output_source_filename_data);
 
-  /* Flag of whether we're printing the first one.  */
-  int first;
+  /* Reset enough state of this object so we can match against a new set of
+     files.  The existing regular expression is retained though.  */
+  void reset_output ()
+  {
+    m_first = true;
+    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);
 
+  /* Prints the header messages for the source files that will be printed
+     with the matching info present in the current object state.
+     SYMBOL_MSG is a message that describes what will or has been done with
+     the symbols of the matching source files.  */
+  void print_header (const char *symbol_msg);
+
   /* An overload suitable for use as a callback to
      quick_symbol_functions::map_symbol_filenames.  */
   void operator() (const char *filename, const char *fullname)
   {
     output (fullname != nullptr ? fullname : filename);
   }
+
+private:
+
+  /* Set the current regular expression, used for matching against files,
+     to REGEXP.  */
+  void set_regexp (const std::string regexp)
+  {
+    m_regexp = std::move (regexp);
+    if (!m_regexp.empty ())
+      {
+	int cflags = REG_NOSUB;
+#ifdef HAVE_CASE_INSENSITIVE_FILE_SYSTEM
+	cflags |= REG_ICASE;
+#endif
+	m_c_regexp.emplace (m_regexp.c_str (), cflags,
+			  _("Invalid regexp"));
+      }
+  }
+
+  /* Output only filenames matching REGEXP.  */
+  std::string m_regexp;
+  gdb::optional<compiled_regex> m_c_regexp;
+
+  /* Flag of whether we're printing the first one.  */
+  bool m_first = true;
+
+  /* Cache of what we've seen so far.  */
+  filename_seen_cache m_filename_seen_cache;
+
+  /* Possibly only match a part of the filename.  */
+  filename_partial_match_opts m_partial_match;
 };
 
+/* See comment is class declaration above.  */
+
 void
 output_source_filename_data::output (const char *name)
 {
@@ -4253,41 +4302,62 @@ output_source_filename_data::output (const char *name)
      symtabs; it doesn't hurt to check.  */
 
   /* Was NAME already seen?  */
-  if (filename_seen_cache->seen (name))
+  if (m_filename_seen_cache.seen (name))
     {
       /* Yes; don't print it again.  */
       return;
     }
 
   /* Does it match regexp?  */
-  if (c_regexp.has_value ())
+  if (m_c_regexp.has_value ())
     {
       const char *to_match;
       std::string dirname;
 
-      if (partial_match.dirname)
+      if (m_partial_match.dirname)
 	{
 	  dirname = ldirname (name);
 	  to_match = dirname.c_str ();
 	}
-      else if (partial_match.basename)
+      else if (m_partial_match.basename)
 	to_match = lbasename (name);
       else
 	to_match = name;
 
-      if (c_regexp->exec (to_match, 0, NULL, 0) != 0)
+      if (m_c_regexp->exec (to_match, 0, NULL, 0) != 0)
 	return;
     }
 
   /* Print it and reset *FIRST.  */
-  if (! first)
+  if (!m_first)
     printf_filtered (", ");
-  first = 0;
+  m_first = false;
 
   wrap_here ("");
   fputs_styled (name, file_name_style.style (), gdb_stdout);
 }
 
+/* See comment is class declaration above.  */
+
+void
+output_source_filename_data::print_header (const char *symbol_msg)
+{
+  puts_filtered (symbol_msg);
+  if (!m_regexp.empty ())
+    {
+      if (m_partial_match.dirname)
+	printf_filtered (_("(dirname matching regular expression \"%s\")"),
+			 m_regexp.c_str ());
+      else if (m_partial_match.basename)
+	printf_filtered (_("(basename matching regular expression \"%s\")"),
+			 m_regexp.c_str ());
+      else
+	printf_filtered (_("(filename matching regular expression \"%s\")"),
+			 m_regexp.c_str ());
+    }
+  puts_filtered ("\n");
+}
+
 using isrc_flag_option_def
   = gdb::option::flag_option_def<filename_partial_match_opts>;
 
@@ -4316,31 +4386,6 @@ make_info_sources_options_def_group (filename_partial_match_opts *isrc_opts)
   return {{info_sources_option_defs}, isrc_opts};
 }
 
-/* Prints the header message for the source files that will be printed
-   with the matching info present in DATA.  SYMBOL_MSG is a message
-   that tells what will or has been done with the symbols of the
-   matching source files.  */
-
-static void
-print_info_sources_header (const char *symbol_msg,
-			   const struct output_source_filename_data *data)
-{
-  puts_filtered (symbol_msg);
-  if (!data->regexp.empty ())
-    {
-      if (data->partial_match.dirname)
-	printf_filtered (_("(dirname matching regular expression \"%s\")"),
-			 data->regexp.c_str ());
-      else if (data->partial_match.basename)
-	printf_filtered (_("(basename matching regular expression \"%s\")"),
-			 data->regexp.c_str ());
-      else
-	printf_filtered (_("(filename matching regular expression \"%s\")"),
-			 data->regexp.c_str ());
-    }
-  puts_filtered ("\n");
-}
-
 /* Completer for "info sources".  */
 
 static void
@@ -4354,49 +4399,33 @@ info_sources_command_completer (cmd_list_element *ignore,
     return;
 }
 
+/* Implement the 'info sources' command.  */
+
 static void
 info_sources_command (const char *args, int from_tty)
 {
-  struct output_source_filename_data data;
-
   if (!have_full_symbols () && !have_partial_symbols ())
-    {
-      error (_("No symbol table is loaded.  Use the \"file\" command."));
-    }
-
-  filename_seen_cache filenames_seen;
-
-  auto group = make_info_sources_options_def_group (&data.partial_match);
+    error (_("No symbol table is loaded.  Use the \"file\" command."));
 
+  struct filename_partial_match_opts match_opts;
+  auto group = make_info_sources_options_def_group (&match_opts);
   gdb::option::process_options
     (&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR, group);
 
-  if (args != NULL && *args != '\000')
-    data.regexp = args;
+  if (match_opts.dirname && match_opts.basename)
+    error (_("You cannot give both -basename and -dirname to 'info sources'."));
 
-  data.filename_seen_cache = &filenames_seen;
-  data.first = 1;
+  const char *regex = nullptr;
+  if (args != nullptr && *args != '\000')
+    regex = args;
 
-  if (data.partial_match.dirname && data.partial_match.basename)
-    error (_("You cannot give both -basename and -dirname to 'info sources'."));
-  if ((data.partial_match.dirname || data.partial_match.basename)
-      && data.regexp.empty ())
-     error (_("Missing REGEXP for 'info sources'."));
+  if ((match_opts.dirname || match_opts.basename) && regex == nullptr)
+    error (_("Missing REGEXP for 'info sources'."));
 
-  if (data.regexp.empty ())
-    data.c_regexp.reset ();
-  else
-    {
-      int cflags = REG_NOSUB;
-#ifdef HAVE_CASE_INSENSITIVE_FILE_SYSTEM
-      cflags |= REG_ICASE;
-#endif
-      data.c_regexp.emplace (data.regexp.c_str (), cflags,
-			     _("Invalid regexp"));
-    }
+  struct output_source_filename_data data (regex, match_opts.dirname,
+					   match_opts.basename);
 
-  print_info_sources_header
-    (_("Source files for which symbols have been read in:\n"), &data);
+  data.print_header (_("Source files for which symbols have been read in:\n"));
 
   for (objfile *objfile : current_program_space->objfiles ())
     {
@@ -4412,11 +4441,9 @@ info_sources_command (const char *args, int from_tty)
     }
   printf_filtered ("\n\n");
 
-  print_info_sources_header
-    (_("Source files for which symbols will be read in on demand:\n"), &data);
+  data.print_header (_("Source files for which symbols will be read in on demand:\n"));
 
-  filenames_seen.clear ();
-  data.first = 1;
+  data.reset_output ();
   map_symbol_filenames (data, true /*need_fullname*/);
   printf_filtered ("\n");
 }
-- 
2.25.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 3/4] gdb: add new -group-by-binary flag to info sources command
  2021-04-26 17:06 [PATCH 0/4] New option for 'info sources', also better MI support Andrew Burgess
  2021-04-26 17:07 ` [PATCH 1/4] gdb: add new function quick_symbol_functions::has_unexpanded_symbols Andrew Burgess
  2021-04-26 17:07 ` [PATCH 2/4] gdb: make struct output_source_filename_data more C++ like Andrew Burgess
@ 2021-04-26 17:07 ` Andrew Burgess
  2021-04-26 17:34   ` Eli Zaretskii
  2021-05-13 15:05   ` Simon Marchi
  2021-04-26 17:07 ` [PATCH 4/4] gdb/mi: extend -file-list-exec-source-files command Andrew Burgess
                   ` (2 subsequent siblings)
  5 siblings, 2 replies; 38+ messages in thread
From: Andrew Burgess @ 2021-04-26 17:07 UTC (permalink / raw)
  To: gdb-patches

Currently the 'info sources' command lists all of the known source
files together, regardless of their source, e.g. here is a session
debugging a test application that makes use of a shared library:

  (gdb) info sources
  Source files for which symbols have been read in:

  /tmp/info-sources/test.c, /usr/include/stdc-predef.h,
  /tmp/info-sources/header.h, /tmp/info-sources/helper.c

  Source files for which symbols will be read in on demand:

  (gdb)

In this commit I add a new flag to the 'info sources' command,
'-group-by-binary'.  When this flag is provided the results are
grouped by the binary file that uses that source file.  Here's the
same session using the new flag:

  (gdb) info sources -group-by-binary
  /tmp/info-sources/test.x:

  /tmp/info-sources/test.c, /usr/include/stdc-predef.h,
  /tmp/info-sources/header.h

  /lib64/ld-linux-x86-64.so.2:
  (Full debug information has not yet been read for this file.)

  system-supplied DSO at 0x7ffff7fcf000:
  (Full debug information has not yet been read for this file.)

  /tmp/info-sources/libhelper.so:

  /tmp/info-sources/helper.c, /usr/include/stdc-predef.h,
  /tmp/info-sources/header.h

  /lib64/libc.so.6:
  (Full debug information has not yet been read for this file.)

  (gdb)

Notice that in the new output some source files are repeated,
e.g. /tmp/info-sources/header.h, as multiple binaries use this source
file.

All of the existing regular expression based filtering that exists for
'info sources' still works with the new option.

gdb/ChangeLog:

	* NEWS: Mention new 'info sources' option.
	* symtab.c (struct filename_grouping_opts): New struct.
	(struct output_source_filename_data) <printed_filename_p>: New
	member function.
	(isrc_flag_option_def): Rename to...
	(isrc_match_flag_option_def): ...this.
	(info_sources_option_defs): Rename to...
	(info_sources_match_option_defs): ...this.  Update to take account
	of isrc_flag_option_def being renamed.
	(isrc_grouping_flag_option_def): New typedef.
	(info_sources_grouping_option_defs): New static global.
	(make_info_sources_options_def_group): Update to take two
	parameters, and return an array.
	(info_sources_command_completer): Update for changes to
	make_info_sources_options_def_group.
	(info_sources_command): Update to display results grouped by
	objfile name if the user supplies the required flag.
	(_initialize_symtab): Update for changes to
	make_info_sources_options_def_group.

gdb/doc/ChangeLog:

	* gdb.textinfo (Symbols): Merge two descriptions of 'info
	sources', and add description of new '-group-by-binary' flag.

gdb/testsuite/ChangeLog:

	* gdb.base/info_sources.exp: Add additional test.
	* gdb.base/info_sources_2-header.h: New file.
	* gdb.base/info_sources_2-lib.c: New file.
	* gdb.base/info_sources_2-test.c: New file.
	* gdb.base/info_sources_2.exp: New file.
---
 gdb/ChangeLog                                 |  22 +++
 gdb/NEWS                                      |   7 +
 gdb/doc/ChangeLog                             |   5 +
 gdb/doc/gdb.texinfo                           |  37 ++--
 gdb/symtab.c                                  |  92 ++++++++--
 gdb/testsuite/ChangeLog                       |   8 +
 gdb/testsuite/gdb.base/info_sources.exp       |   5 +
 .../gdb.base/info_sources_2-header.h          |  28 +++
 gdb/testsuite/gdb.base/info_sources_2-lib.c   |  25 +++
 gdb/testsuite/gdb.base/info_sources_2-test.c  |  26 +++
 gdb/testsuite/gdb.base/info_sources_2.exp     | 169 ++++++++++++++++++
 11 files changed, 393 insertions(+), 31 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/info_sources_2-header.h
 create mode 100644 gdb/testsuite/gdb.base/info_sources_2-lib.c
 create mode 100644 gdb/testsuite/gdb.base/info_sources_2-test.c
 create mode 100644 gdb/testsuite/gdb.base/info_sources_2.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index 1cdf19c09a0..f84ea0427a7 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -157,6 +157,13 @@ ptype[/FLAGS] TYPE | EXPRESSION
   offsets of struct members.  Default behavior is given by 'show print
   type hex'.
 
+info sources [-group-by-binary] [-dirname] [-basename] [REGEXP]
+  The 'info sources' command now supports a new flag
+  '-group-by-binary'.  When this flag is supplied the results are
+  formatted as a list of loaded binaries followed by the source files
+  for each binary.  A single source file can appear multiple times in
+  the output if it is part of multiple binaries.
+
 * Removed targets and native configurations
 
 ARM Symbian			arm*-*-symbianelf*
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index a068de6c95b..03bf603ad42 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -19335,20 +19335,29 @@
 
 
 @kindex info sources
-@item info sources
-Print the names of all source files in your program for which there is
-debugging information, organized into two lists: files whose symbols
-have already been read, and files whose symbols will be read when needed.
-
-@item info sources [-dirname | -basename] [--] [@var{regexp}]
-Like @samp{info sources}, but only print the names of the files
-matching the provided @var{regexp}.
-By default, the @var{regexp} is used to match anywhere in the filename.
-If @code{-dirname}, only files having a dirname matching @var{regexp} are shown.
-If  @code{-basename}, only files having a basename matching @var{regexp}
-are shown.
-The matching is case-sensitive, except on operating systems that
-have case-insensitive filesystem (e.g., MS-Windows).
+@item info sources @r{[}-group-by-binary@r{]} @r{[}-dirname | -basename@r{]} @r{[}--@r{]} @r{[}@var{regexp}@r{]}
+With no options @samp{info sources} prints the names of all source
+files in your program for which there is debugging information,
+organized into two lists: files whose symbols have already been read,
+and files whose symbols will be read when needed.
+
+When the optional @code{-group-by-binary} flag is given then the
+output is organized as a list of the binaries currently loaded into
+@value{GDBN}, for each binary, all of the source files associated with
+that binary are given.  A single source file can be repeated in this
+output format, if it is part of multiple binaries.
+
+If the optional @var{regexp} is provided, then only source files that
+match the regular expression will be printed.  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{-}).
+
+By default, the @var{regexp} is used to match anywhere in the
+filename.  If @code{-dirname}, only files having a dirname matching
+@var{regexp} are shown.  If @code{-basename}, only files having a
+basename matching @var{regexp} are shown.
 
 @kindex info functions
 @item info functions [-q] [-n]
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 5650d225752..d8d0667dfdb 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4212,6 +4212,14 @@ struct filename_partial_match_opts
   bool basename = false;
 };
 
+/* For the 'info sources' command, should the results be grouped by objfile
+   name?  */
+struct filename_grouping_opts
+{
+  /* Group source files by the containing binary.  */
+  bool group_by_binary = false;
+};
+
 /* Data structure to maintain the state used for printing the results of
    the 'info sources' command.  */
 
@@ -4255,6 +4263,14 @@ struct output_source_filename_data
     output (fullname != nullptr ? fullname : filename);
   }
 
+  /* Return true if at least one filename has been printed (after a call to
+     output) since either this object was created, or the last call to
+     reset_output.  */
+  bool printed_filename_p () const
+  {
+    return !m_first;
+  }
+
 private:
 
   /* Set the current regular expression, used for matching against files,
@@ -4358,18 +4374,18 @@ output_source_filename_data::print_header (const char *symbol_msg)
   puts_filtered ("\n");
 }
 
-using isrc_flag_option_def
+using isrc_match_flag_option_def
   = gdb::option::flag_option_def<filename_partial_match_opts>;
 
-static const gdb::option::option_def info_sources_option_defs[] = {
+static const gdb::option::option_def info_sources_match_option_defs[] = {
 
-  isrc_flag_option_def {
+  isrc_match_flag_option_def {
     "dirname",
     [] (filename_partial_match_opts *opts) { return &opts->dirname; },
     N_("Show only the files having a dirname matching REGEXP."),
   },
 
-  isrc_flag_option_def {
+  isrc_match_flag_option_def {
     "basename",
     [] (filename_partial_match_opts *opts) { return &opts->basename; },
     N_("Show only the files having a basename matching REGEXP."),
@@ -4377,13 +4393,31 @@ static const gdb::option::option_def info_sources_option_defs[] = {
 
 };
 
+using isrc_grouping_flag_option_def
+  = gdb::option::flag_option_def<filename_grouping_opts>;
+
+static const gdb::option::option_def info_sources_grouping_option_defs[] = {
+
+  isrc_grouping_flag_option_def {
+    "group-by-binary",
+    [] (filename_grouping_opts *opts) { return &opts->group_by_binary; },
+    N_("Group source files by the binary they are from."),
+  },
+
+};
+
 /* Create an option_def_group for the "info sources" options, with
    ISRC_OPTS as context.  */
 
-static inline gdb::option::option_def_group
-make_info_sources_options_def_group (filename_partial_match_opts *isrc_opts)
+static inline std::array<gdb::option::option_def_group, 2>
+make_info_sources_options_def_group
+	(filename_partial_match_opts *isrc_match_opts,
+	 filename_grouping_opts *isrc_grp_opts)
 {
-  return {{info_sources_option_defs}, isrc_opts};
+  return {{
+      {{info_sources_match_option_defs}, isrc_match_opts},
+      {{info_sources_grouping_option_defs}, isrc_grp_opts},
+    }};
 }
 
 /* Completer for "info sources".  */
@@ -4393,7 +4427,7 @@ info_sources_command_completer (cmd_list_element *ignore,
 				completion_tracker &tracker,
 				const char *text, const char *word)
 {
-  const auto group = make_info_sources_options_def_group (nullptr);
+  const auto group = make_info_sources_options_def_group (nullptr, nullptr);
   if (gdb::option::complete_options
       (tracker, &text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, group))
     return;
@@ -4407,14 +4441,17 @@ info_sources_command (const char *args, int from_tty)
   if (!have_full_symbols () && !have_partial_symbols ())
     error (_("No symbol table is loaded.  Use the \"file\" command."));
 
+  struct filename_grouping_opts grp_opts;
   struct filename_partial_match_opts match_opts;
-  auto group = make_info_sources_options_def_group (&match_opts);
+  auto group = make_info_sources_options_def_group (&match_opts, &grp_opts);
   gdb::option::process_options
     (&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR, group);
 
   if (match_opts.dirname && match_opts.basename)
     error (_("You cannot give both -basename and -dirname to 'info sources'."));
 
+  bool group_by_binary = grp_opts.group_by_binary;
+
   const char *regex = nullptr;
   if (args != nullptr && *args != '\000')
     regex = args;
@@ -4425,27 +4462,47 @@ info_sources_command (const char *args, int from_tty)
   struct output_source_filename_data data (regex, match_opts.dirname,
 					   match_opts.basename);
 
-  data.print_header (_("Source files for which symbols have been read in:\n"));
+  if (!group_by_binary)
+    data.print_header (_("Source files for which symbols have been read in:\n"));
 
   for (objfile *objfile : current_program_space->objfiles ())
     {
+      if (group_by_binary)
+	{
+	  printf_filtered ("%s:\n", objfile_name (objfile));
+	  bool debug_fully_readin = !objfile->has_unexpanded_symbols ();
+	  if (!debug_fully_readin)
+	    printf_filtered ("(Full debug information has not yet been read for this file.)\n");
+	  printf_filtered ("\n");
+	}
+
       for (compunit_symtab *cu : objfile->compunits ())
 	{
 	  for (symtab *s : compunit_filetabs (cu))
 	    {
 	      const char *fullname = symtab_to_fullname (s);
-
 	      data.output (fullname);
 	    }
 	}
+
+      if (group_by_binary)
+	{
+	  objfile->map_symbol_filenames (data, true /* need_fullname */);
+	  if (data.printed_filename_p ())
+	    printf_filtered ("\n\n");
+	  data.reset_output ();
+	}
     }
-  printf_filtered ("\n\n");
 
-  data.print_header (_("Source files for which symbols will be read in on demand:\n"));
+  if (!group_by_binary)
+    {
+      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");
+      data.reset_output ();
+      map_symbol_filenames (data, true /*need_fullname*/);
+      printf_filtered ("\n");
+    }
 }
 
 /* Compare FILE against all the entries of FILENAMES.  If BASENAMES is
@@ -6805,7 +6862,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, nullptr);
 
   static std::string info_sources_help
     = gdb::option::build_help (_("\
diff --git a/gdb/testsuite/gdb.base/info_sources.exp b/gdb/testsuite/gdb.base/info_sources.exp
index a4f7d1966e6..659a1a4368c 100644
--- a/gdb/testsuite/gdb.base/info_sources.exp
+++ b/gdb/testsuite/gdb.base/info_sources.exp
@@ -103,3 +103,8 @@ if { ! [is_remote host] } {
 # Test non matching regexp, with option terminator:
 test_info_sources "-b -- -d" 0 0
 test_info_sources "-d -- -d" 0 0
+
+# Test with the -group-by-binary option.
+test_info_sources "-group-by-binary" 1 1
+test_info_sources "-group-by-binary -basename info_sources" 1 1
+test_info_sources "-group-by-binary -basename base" 0 1
diff --git a/gdb/testsuite/gdb.base/info_sources_2-header.h b/gdb/testsuite/gdb.base/info_sources_2-header.h
new file mode 100644
index 00000000000..b3379babc0a
--- /dev/null
+++ b/gdb/testsuite/gdb.base/info_sources_2-header.h
@@ -0,0 +1,28 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   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/>.  */
+
+#ifndef INFO_SOURCES_2_HEADER
+#define INFO_SOURCES_2_HEADER
+
+extern int foo (void);
+
+inline static int compare_values (int a, int b)
+{
+  return a == b;
+}
+
+#endif /* INFO_SOURCES_2_HEADER */
diff --git a/gdb/testsuite/gdb.base/info_sources_2-lib.c b/gdb/testsuite/gdb.base/info_sources_2-lib.c
new file mode 100644
index 00000000000..7df1a8114ad
--- /dev/null
+++ b/gdb/testsuite/gdb.base/info_sources_2-lib.c
@@ -0,0 +1,25 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   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/>.  */
+
+
+#include "info_sources_2-header.h"
+
+int
+foo ()
+{
+  return compare_values (0, 1);
+}
diff --git a/gdb/testsuite/gdb.base/info_sources_2-test.c b/gdb/testsuite/gdb.base/info_sources_2-test.c
new file mode 100644
index 00000000000..87a030ae87d
--- /dev/null
+++ b/gdb/testsuite/gdb.base/info_sources_2-test.c
@@ -0,0 +1,26 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   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/>.  */
+
+
+#include "info_sources_2-header.h"
+
+int
+main ()
+{
+  int res = foo ();
+  return compare_values (res, 1);
+}
diff --git a/gdb/testsuite/gdb.base/info_sources_2.exp b/gdb/testsuite/gdb.base/info_sources_2.exp
new file mode 100644
index 00000000000..dd4f4f08263
--- /dev/null
+++ b/gdb/testsuite/gdb.base/info_sources_2.exp
@@ -0,0 +1,169 @@
+# 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 'info sources -group-by-binary' when the test file makes use of
+# a shared library.
+
+if { [skip_shlib_tests] } {
+    return 0
+}
+
+standard_testfile -test.c -lib.c
+set solib_name [standard_output_file ${testfile}-lib.so]
+
+if { [gdb_compile_shlib ${srcdir}/${subdir}/${srcfile2} ${solib_name} \
+      {debug}] != "" } {
+    untested "failed to compile shared library"
+    return -1
+}
+
+if {[gdb_compile ${srcdir}/${subdir}/${srcfile} ${binfile} executable \
+     [list debug shlib=${solib_name} ]] != ""} {
+    untested "failed to compile executable"
+    return -1
+}
+
+clean_restart ${binfile}
+
+if ![runto foo] {
+    untested "failed to run to function foo"
+    return -1
+}
+
+# Invoke 'info sources -group-by-binary EXTRA_ARGS' and extract the results.
+# The results are then compared to the list ARGS.
+#
+# The list ARGS should consist of pairs of values, the first item being the
+# path to an object file, and the second item being the name of a source file.
+# This proc checks that source file was listed as being a source file for the
+# given object file.
+#
+# If the name of the source file starts with the character "!" (exclamation
+# character, without the quotes) then the check is inverted, that the source
+# file is NOT listed for the given object file.
+proc run_info_sources { extra_args args } {
+    global gdb_prompt srcdir subdir
+
+    with_test_prefix "args: ${extra_args}" {
+
+	# The results of running info sources will be placed into this local.
+	array set info_sources {}
+
+	# The command we are going to run.
+	set cmd "info sources -group-by-binary ${extra_args}"
+	set command_regex [string_to_regexp $cmd]
+
+	# Run the command and extract the results into INFO_SOURCES.
+	set objfile_name ""
+	set source_files {}
+	gdb_test_multiple $cmd "" {
+	    -re "${command_regex}\r\n" {
+		exp_continue
+	    }
+
+	    -re "^(\[^\r\n\]+):\r\n" {
+		set objfile_name $expect_out(1,string)
+		exp_continue
+	    }
+
+	    -re "^\\(Full debug information has not yet been read for this file\\.\\)\r\n" {
+		exp_continue
+	    }
+
+	    -re "^\r\n" {
+		exp_continue
+	    }
+
+	    -re "^$gdb_prompt $" {
+		pass $gdb_test_name
+	    }
+
+	    -re "^(\[^\r\n\]+)\r\n" {
+		if { $objfile_name == "" } {
+		    fail "${gdb_test_name} (no objfile name)"
+		    return
+		}
+
+		set files {}
+		foreach f [split $expect_out(1,string) ,] {
+		    lappend files [string trim $f]
+		}
+		set info_sources($objfile_name) $files
+		set $objfile_name ""
+		exp_continue
+	    }
+	}
+
+	# Now check ARGS agaisnt the values held in INFO_SOURCES map.
+	foreach {objfile sourcefile} $args {
+	    # First, figure out if we're expecting SOURCEFILE to be present,
+	    # or not.
+	    set present True
+	    set match_type "is"
+	    if {[string index $sourcefile 0] == "!"} {
+		set present False
+		set match_type "is not"
+		set sourcefile [string range $sourcefile 1 end]
+	    }
+
+	    # Figure out the path for SOURCEFILE that we're looking for.
+	    set sourcepath [file normalize ${srcdir}/${subdir}/${sourcefile}]
+
+	    # Make sure we handle the case where there are no source files
+	    # associated with a particular objfile.
+	    set source_list {}
+	    if [info exists info_sources($objfile)] {
+		set source_list $info_sources($objfile)
+	    }
+
+	    # Now perform the search, and check the results.
+	    set idx [lsearch -exact $source_list $sourcepath]
+	    gdb_assert {($present && $idx >= 0) || (!$present && $idx == -1)} \
+		"source file '$sourcefile' ${match_type} present for '[file tail $objfile]'"
+	}
+    }
+}
+
+# The actual tests.
+
+run_info_sources "" \
+    ${binfile} ${srcfile} \
+    ${binfile} ${testfile}-header.h \
+    ${solib_name} ${srcfile2} \
+    ${solib_name} ${testfile}-header.h
+
+run_info_sources "-basename info_sources_2" \
+    ${binfile} ${srcfile} \
+    ${binfile} ${testfile}-header.h \
+    ${solib_name} ${srcfile2} \
+    ${solib_name} ${testfile}-header.h
+
+run_info_sources "-basename \\.c" \
+    ${binfile} ${srcfile} \
+    ${binfile} !${testfile}-header.h \
+    ${solib_name} ${srcfile2} \
+    ${solib_name} !${testfile}-header.h
+
+run_info_sources "-basename -- -test\\.c" \
+    ${binfile} ${srcfile} \
+    ${binfile} !${testfile}-header.h \
+    ${solib_name} !${srcfile2} \
+    ${solib_name} !${testfile}-header.h
+
+run_info_sources "-basename -- -lib\\.c" \
+    ${binfile} !${srcfile} \
+    ${binfile} !${testfile}-header.h \
+    ${solib_name} ${srcfile2} \
+    ${solib_name} !${testfile}-header.h
-- 
2.25.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCH 4/4] gdb/mi: extend -file-list-exec-source-files command
  2021-04-26 17:06 [PATCH 0/4] New option for 'info sources', also better MI support Andrew Burgess
                   ` (2 preceding siblings ...)
  2021-04-26 17:07 ` [PATCH 3/4] gdb: add new -group-by-binary flag to info sources command Andrew Burgess
@ 2021-04-26 17:07 ` Andrew Burgess
  2021-04-26 17:39   ` Eli Zaretskii
  2021-05-13 15:47   ` Simon Marchi
  2021-05-13 10:34 ` [PATCH 0/4] New option for 'info sources', also better MI support Andrew Burgess
  2021-05-19 11:12 ` [PATCHv2 0/5] "info sources" - group by objfile Andrew Burgess
  5 siblings, 2 replies; 38+ messages in thread
From: Andrew Burgess @ 2021-04-26 17:07 UTC (permalink / raw)
  To: gdb-patches

This commit extends the -file-list-exec-source-files command to
support all of the features that the cli 'info sources' supports.

As this is MI the output of -file-list-exec-source-files should be
backward compatible, though I have added an extra field into the
output format, but I believe this is acceptable as a well behaving
front end is free to ignore a field it doesn't understand.

As an example, the previous output might look like this:

  ^done,files=[{file="foo.c",fullname="/home/foo.c"}]

While the new output would look like:

  ^done,files=[{file="foo.c",fullname="/home/foo.c",debug-fully-read="true"}]

With the new field indicating that the source file 'foo.c' is from a
compilation unit that GDB has fully read in.

This would allow a front end to recreate GDB's cli output format where
the source files are split into two groups based on whether the debug
information for the containing compilation unit has been fully read or
not.

While -file-list-exec-source-files previously took no arguments, after
this commit the command can _optionally_ take some arguments, as these
are optional this should not break backward compatibility.

gdb/ChangeLog:

	* NEWS: Mention changes 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 make use of
	info_sources_worker.
	* symtab.c (struct output_source_filename_data) <output>: Rewrite
	comment, add additional arguments to declaration.
	(output_source_filename_data::output): Take extra arguments,
	produce output through current_uiout, and structure for MI.
	(info_sources_worker): New function, the implementation is taken
	from info_sources_command, but modified so produce output through
	current_uiout.
	(info_sources_command): The second half of this function has gone
	to become info_sources_worker.
	* symtab.h (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.
---
 gdb/ChangeLog                               |  17 ++
 gdb/NEWS                                    |  11 ++
 gdb/doc/ChangeLog                           |   5 +
 gdb/doc/gdb.texinfo                         | 122 ++++++++++++--
 gdb/mi/mi-cmd-file.c                        |  84 +++++-----
 gdb/symtab.c                                | 150 ++++++++++++-----
 gdb/symtab.h                                |  24 +++
 gdb/testsuite/ChangeLog                     |   8 +
 gdb/testsuite/gdb.dwarf2/dw2-filename.exp   |   2 +-
 gdb/testsuite/gdb.mi/mi-file.exp            |   2 +-
 gdb/testsuite/gdb.mi/mi-info-sources-base.c |  24 +++
 gdb/testsuite/gdb.mi/mi-info-sources.c      |  25 +++
 gdb/testsuite/gdb.mi/mi-info-sources.exp    | 177 ++++++++++++++++++++
 13 files changed, 554 insertions(+), 97 deletions(-)
 create mode 100644 gdb/testsuite/gdb.mi/mi-info-sources-base.c
 create mode 100644 gdb/testsuite/gdb.mi/mi-info-sources.c
 create mode 100644 gdb/testsuite/gdb.mi/mi-info-sources.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index f84ea0427a7..288c399747e 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -31,6 +31,17 @@
     equivalent of the CLI's "break -qualified" and "dprintf
     -qualified".
 
+  ** '-file-list-exec-source-files' can now accept a regular
+     expression for filtering, and accepts the flags --dirname,
+     --basename and --group-by-binary, making this command equivalent
+     of the cli 'info sources' command.
+
+     In the non '--group-by-binary' mode an extra field
+     'debug-fully-read' has been added to each source file tuple to
+     indicate if the debug information for the compilation unit
+     containing this source file has been fully read or not, the
+     values for this field are 'true' or 'false'.
+
 * GDB now supports core file debugging for x86_64 Cygwin programs.
 
 * GDB will now look for the .gdbinit file in a config directory before
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 03bf603ad42..8da63959ede 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -35625,18 +35625,63 @@
 
 
 @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
-
-List the source files for the current executable.
+-file-list-exec-source-files @r{[} @var{--group-by-binary} @r{]}
+                             @r{[} @var{--dirname} @r{|} @var{--basename} @r{]}
+                             @r{[} -- @r{]}
+                             @r{[} @var{regexp} @r{]}
+@end smallexample
+
+This commands 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.
+
+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 path
+to the file.  The @var{fullname} field can be elided if the absolute
+path to 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.
 
-It will always output both the filename and fullname (absolute file
-name) of a source file.
+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{-}).
+
+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 source files
+basename.  Only one of @code{--dirname} or @code{--basename} may be
+given, and if either is given then @var{regexp} is required.
+
+If @code{--group-by-binary} is used then the format of the results is
+changed.  The results will now be a list of tuples, with each tuple
+representing an object file (executable or shared libraries) loaded
+into @value{GDBN}.  The fields of these tuples are; @var{filename},
+@var{debug-fully-read}, and @var{sources}.  The @var{filename} is the
+absolute path to the object file, @var{debug-fully-read} is a string,
+either @code{true} or @code{false} indicating if the full debug
+information for this object file has been read in or not.  The
+@var{sources} is a list or tuples, with each tuple describing a single
+source file with the same fields as described previously.  The
+@var{sources} list can be empty for object files that have no debug
+information.
 
 @subsubheading @value{GDBN} Command
 
@@ -35645,13 +35690,66 @@
 
 @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})
+-file-list-exec-source-files --group-by-binary
+^done,files=[@{filename="/tmp/info-sources/test.x",
+              debug-fully-read="true",
+              sources=[@{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"@}]@},
+             @{filename="/lib64/ld-linux-x86-64.so.2",
+              debug-fully-read="true",
+              sources=[]@},
+             @{filename="system-supplied DSO at 0x7ffff7fcf000",
+              debug-fully-read="true",
+              sources=[]@},
+             @{filename="/tmp/info-sources/libhelper.so",
+              debug-fully-read="true",
+              sources=[@{file="helper.c",
+                        fullname="/tmp/info-sources/helper.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"@}]@},
+             @{filename="/lib64/libc.so.6",
+              debug-fully-read="true",
+              sources=[]@}]
 @end smallexample
 
 @subheading The @code{-file-list-shared-libraries} Command
diff --git a/gdb/mi/mi-cmd-file.c b/gdb/mi/mi-cmd-file.c
index 430449c919e..f4c1443c3e4 100644
--- a/gdb/mi/mi-cmd-file.c
+++ b/gdb/mi/mi-cmd-file.c
@@ -62,54 +62,62 @@ 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
     {
-      for (compunit_symtab *cu : objfile->compunits ())
+      GROUP_BY_BINARY_OPT,
+      MATCH_BASENAME_OPT,
+      MATCH_DIRNAME_OPT
+    };
+  static const struct mi_opt opts[] =
+  {
+    {"-group-by-binary", GROUP_BY_BINARY_OPT, 0},
+    {"-basename", MATCH_BASENAME_OPT, 0},
+    {"-dirname", MATCH_DIRNAME_OPT, 0},
+    { 0, 0, 0 }
+  };
+
+  /* Parse arguments.  */
+  int oind = 0;
+  char *oarg;
+
+  bool group_by_binary = false;
+  bool match_on_basename = false;
+  bool match_on_dirname = false;
+
+  while (1)
+    {
+      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 GROUP_BY_BINARY_OPT:
+	  group_by_binary = true;
+	  break;
+	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: [--group-by-binary] [--basename | --dirname] [--] REGEXP"));
+
+  const char *regexp = nullptr;
+  if (argc - oind == 1)
+    regexp = argv[oind];
 
-  uiout->end (ui_out_type_list);
+  info_sources_worker (group_by_binary, match_on_basename,
+		       match_on_dirname, regexp);
 }
 
 /* See mi-cmds.h.  */
diff --git a/gdb/symtab.c b/gdb/symtab.c
index d8d0667dfdb..e1a96fbb0c0 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4246,9 +4246,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.
@@ -4260,7 +4265,7 @@ struct output_source_filename_data
      quick_symbol_functions::map_symbol_filenames.  */
   void operator() (const char *filename, const char *fullname)
   {
-    output (fullname != nullptr ? fullname : filename);
+    output (filename, fullname, false);
   }
 
   /* Return true if at least one filename has been printed (after a call to
@@ -4306,7 +4311,9 @@ struct output_source_filename_data
 /* See comment is 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
@@ -4318,7 +4325,7 @@ output_source_filename_data::output (const char *name)
      symtabs; it doesn't hurt to check.  */
 
   /* Was NAME already seen?  */
-  if (m_filename_seen_cache.seen (name))
+  if (m_filename_seen_cache.seen (fullname))
     {
       /* Yes; don't print it again.  */
       return;
@@ -4332,25 +4339,43 @@ output_source_filename_data::output (const char *name)
 
       if (m_partial_match.dirname)
 	{
-	  dirname = ldirname (name);
+	  dirname = ldirname (fullname);
 	  to_match = dirname.c_str ();
 	}
       else if (m_partial_match.basename)
-	to_match = lbasename (name);
+	to_match = lbasename (fullname);
       else
-	to_match = name;
+	to_match = fullname;
 
       if (m_c_regexp->exec (to_match, 0, NULL, 0) != 0)
 	return;
     }
 
+  ui_out_emit_tuple ui_emitter (current_uiout, nullptr);
+
   /* Print it and reset *FIRST.  */
   if (!m_first)
-    printf_filtered (", ");
+    current_uiout->text (", ");
   m_first = false;
 
   wrap_here ("");
-  fputs_styled (name, file_name_style.style (), gdb_stdout);
+  if (current_uiout->is_mi_like_p ())
+    {
+      current_uiout->field_string ("file", disp_name,
+				   file_name_style.style ());
+      if (fullname != nullptr)
+	current_uiout->field_string ("fullname", fullname,
+				     file_name_style.style ());
+      current_uiout->field_string ("debug-fully-read",
+				   (expanded_p ? "true" : "false"));
+    }
+  else
+    {
+      if (fullname == nullptr)
+	fullname = disp_name;
+      current_uiout->field_string ("fullname", fullname,
+				   file_name_style.style ());
+    }
 }
 
 /* See comment is class declaration above.  */
@@ -4433,55 +4458,59 @@ info_sources_command_completer (cmd_list_element *ignore,
     return;
 }
 
-/* Implement the 'info sources' command.  */
+/* See symtab.h.  */
 
-static void
-info_sources_command (const char *args, int from_tty)
+void
+info_sources_worker (bool group_by_binary,
+		     bool match_on_basename,
+		     bool match_on_dirname,
+		     const char *regexp)
 {
-  if (!have_full_symbols () && !have_partial_symbols ())
-    error (_("No symbol table is loaded.  Use the \"file\" command."));
+  /* Check for these error conditions before calling this function.  */
+  gdb_assert (!(match_on_basename && match_on_dirname));
+  gdb_assert (((match_on_basename || match_on_dirname) && regexp != nullptr)
+	      || !(match_on_basename || match_on_dirname));
 
-  struct filename_grouping_opts grp_opts;
-  struct filename_partial_match_opts match_opts;
-  auto group = make_info_sources_options_def_group (&match_opts, &grp_opts);
-  gdb::option::process_options
-    (&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR, group);
-
-  if (match_opts.dirname && match_opts.basename)
-    error (_("You cannot give both -basename and -dirname to 'info sources'."));
-
-  bool group_by_binary = grp_opts.group_by_binary;
+  struct output_source_filename_data data (regexp, match_on_dirname,
+					   match_on_basename);
 
-  const char *regex = nullptr;
-  if (args != nullptr && *args != '\000')
-    regex = args;
-
-  if ((match_opts.dirname || match_opts.basename) && regex == nullptr)
-    error (_("Missing REGEXP for 'info sources'."));
-
-  struct output_source_filename_data data (regex, match_opts.dirname,
-					   match_opts.basename);
+  struct ui_out *uiout = current_uiout;
+  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 (!group_by_binary)
-    data.print_header (_("Source files for which symbols have been read in:\n"));
+    {
+      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 ())
     {
       if (group_by_binary)
 	{
-	  printf_filtered ("%s:\n", objfile_name (objfile));
+	  output_tuple.emplace (uiout, nullptr);
+	  uiout->field_string ("filename", objfile_name (objfile));
+	  uiout->text (":\n");
 	  bool debug_fully_readin = !objfile->has_unexpanded_symbols ();
 	  if (!debug_fully_readin)
-	    printf_filtered ("(Full debug information has not yet been read for this file.)\n");
-	  printf_filtered ("\n");
+	    uiout->text ("(Full debug information has not yet been read "
+			 " for this file.)\n");
+	  if (uiout->is_mi_like_p ())
+	    current_uiout->field_string ("debug-fully-read",
+					 (debug_fully_readin
+					  ? "true" : "false"));
+	  uiout->text ("\n");
+	  sources_list.emplace (uiout, "sources");
 	}
 
       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 (fullname);
+	      data.output (file, fullname, true);
 	    }
 	}
 
@@ -4489,22 +4518,53 @@ info_sources_command (const char *args, int from_tty)
 	{
 	  objfile->map_symbol_filenames (data, true /* need_fullname */);
 	  if (data.printed_filename_p ())
-	    printf_filtered ("\n\n");
+	    uiout->text ("\n\n");
 	  data.reset_output ();
+	  sources_list.reset ();
+	  output_tuple.reset ();
 	}
     }
 
   if (!group_by_binary)
     {
-      printf_filtered ("\n\n");
-      data.print_header (_("Source files for which symbols will be read in on demand:\n"));
-
+      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*/);
-      printf_filtered ("\n");
+      uiout->text ("\n");
     }
 }
 
+/* Implement the 'info sources' command.  */
+
+static void
+info_sources_command (const char *args, int from_tty)
+{
+  if (!have_full_symbols () && !have_partial_symbols ())
+    error (_("No symbol table is loaded.  Use the \"file\" command."));
+
+  struct filename_grouping_opts grp_opts;
+  struct filename_partial_match_opts match_opts;
+  auto group = make_info_sources_options_def_group (&match_opts, &grp_opts);
+  gdb::option::process_options
+    (&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR, group);
+
+  if (match_opts.dirname && match_opts.basename)
+    error (_("You cannot give both -basename and -dirname to 'info sources'."));
+
+  const char *regex = nullptr;
+  if (args != NULL && *args != '\000')
+    regex = args;
+
+  if ((match_opts.dirname || match_opts.basename) && regex == nullptr)
+    error (_("Missing REGEXP for 'info sources'."));
+
+  info_sources_worker (grp_opts.group_by_binary,
+		       match_opts.basename, match_opts.dirname,
+		       regex);
+}
+
 /* Compare FILE against all the entries of FILENAMES.  If BASENAMES is
    true compare only lbasename of FILENAMES.  */
 
diff --git a/gdb/symtab.h b/gdb/symtab.h
index efdbada9761..5f767297bb6 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -2384,4 +2384,28 @@ class symbol_searcher
   std::vector<bound_minimal_symbol> m_minimal_symbols;
 };
 
+/* Perform the core of the 'info sources' command.  REGEXP is the regular
+   expression to filter on and can be nullptr if no regular expression
+   filtering is required.
+
+   MATCH_ON_BASENAME and MATCH_ON_DIRNAME control which part of the
+   full filename to match REGEXP against.  If REGEXP is not nullptr and
+   both of the MATCH_ON_* variables are false then matching is done against
+   the full filename.  Only one of the MATCH_ON_* variables is allowed to
+   be true.  If either of these is true then REGEXP must not be nullptr.
+
+   When GROUP_BY_BINARY is true then the results are grouped based on the
+   binary that contains the source file, otherwise the results are just
+   returned in two lists, source files for objfiles where the full debug
+   has been read, and source files for objfiles that have not had the full
+   debug read.
+
+   The output is written to the current_uiout either in CLI or MI style as
+   appropriate.  */
+
+extern void info_sources_worker (bool group_by_binary,
+				 bool match_on_basename,
+				 bool match_on_dirname,
+				 const char *regexp);
+
 #endif /* !defined(SYMTAB_H) */
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-filename.exp b/gdb/testsuite/gdb.dwarf2/dw2-filename.exp
index 3e60f7d2bc9..bd303c8547b 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-filename.exp
+++ b/gdb/testsuite/gdb.dwarf2/dw2-filename.exp
@@ -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.*}
diff --git a/gdb/testsuite/gdb.mi/mi-file.exp b/gdb/testsuite/gdb.mi/mi-file.exp
index 15d7d9f0944..4cae33c017e 100644
--- a/gdb/testsuite/gdb.mi/mi-file.exp
+++ b/gdb/testsuite/gdb.mi/mi-file.exp
@@ -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
index 00000000000..d2e3eb0eace
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-info-sources-base.c
@@ -0,0 +1,24 @@
+/* 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
index 00000000000..b91b8280c2b
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-info-sources.c
@@ -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
index 00000000000..3c478c875c1
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-info-sources.exp
@@ -0,0 +1,177 @@
+# 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"
+
+	set p [mi_list "files" \
+		   [mi_tuple "" \
+			[mi_field "filename" "\[^\"\]+/mi-info-sources"] \
+			[mi_field "debug-fully-read" "${debug_fully_read}"] \
+			[mi_list "sources" \
+			     ".*" \
+			     [mi_tuple "" \
+				  [mi_field "file" "\[^\"\]+/mi-info-sources\\.c"] \
+				  [mi_field "fullname" "\[^\"\]+/mi-info-sources\\.c"] \
+				  [mi_field "debug-fully-read" "true"]] \
+			     ".*"]]]
+	mi_gdb_test "-file-list-exec-source-files --group-by-binary" \
+	    ".*\\^done,${p}" \
+	    "-file-list-exec-source-files --group-by-binary, look for mi-info-sources.c"
+
+	set p [mi_list "files" \
+		   [mi_tuple "" \
+			[mi_field "filename" "\[^\"\]+/mi-info-sources"] \
+			[mi_field "debug-fully-read" "${debug_fully_read}"] \
+			[mi_list "sources" \
+			     ".*" \
+			     [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 --group-by-binary" \
+	    ".*\\^done,${p}" \
+	    "-file-list-exec-source-files --group-by-binary, look for mi-info-sources-base.c"
+    }
+}
+
+check_info_sources "false"
+
+mi_continue_to "some_other_func"
+
+check_info_sources "true"
-- 
2.25.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 3/4] gdb: add new -group-by-binary flag to info sources command
  2021-04-26 17:07 ` [PATCH 3/4] gdb: add new -group-by-binary flag to info sources command Andrew Burgess
@ 2021-04-26 17:34   ` Eli Zaretskii
  2021-05-13 15:05   ` Simon Marchi
  1 sibling, 0 replies; 38+ messages in thread
From: Eli Zaretskii @ 2021-04-26 17:34 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches

> From: Andrew Burgess <andrew.burgess@embecosm.com>
> Date: Mon, 26 Apr 2021 18:07:02 +0100
> 
> +info sources [-group-by-binary] [-dirname] [-basename] [REGEXP]
> +  The 'info sources' command now supports a new flag
> +  '-group-by-binary'.  When this flag is supplied the results are
> +  formatted as a list of loaded binaries followed by the source files
> +  for each binary.  A single source file can appear multiple times in
> +  the output if it is part of multiple binaries.

I'm worried about the confusion we will cause by the "binary"
terminology.  Elsewhere we call these "object files"; see, for
example, "Auto-loading sequences".  Can we keep our terminology
consistent?

> +When the optional @code{-group-by-binary} flag is given then the
> +output is organized as a list of the binaries currently loaded into
> +@value{GDBN}, for each binary, all of the source files associated with
> +that binary are given.  A single source file can be repeated in this
> +output format, if it is part of multiple binaries.

And here you don't even explain what is a "binary" for this purpose.

> +If the optional @var{regexp} is provided, then only source files that
> +match the regular expression will be printed.  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{-}).

I wonder how the new output will look when REGEXP is given.  Suppose
some binary has no sources that match the regexp: will that binary
appear with an empty list of source files, or will it not appear at
all?  And if the latter, isn't it confusing?

Thanks.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 4/4] gdb/mi: extend -file-list-exec-source-files command
  2021-04-26 17:07 ` [PATCH 4/4] gdb/mi: extend -file-list-exec-source-files command Andrew Burgess
@ 2021-04-26 17:39   ` Eli Zaretskii
  2021-05-13 15:47   ` Simon Marchi
  1 sibling, 0 replies; 38+ messages in thread
From: Eli Zaretskii @ 2021-04-26 17:39 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches

> From: Andrew Burgess <andrew.burgess@embecosm.com>
> Date: Mon, 26 Apr 2021 18:07:03 +0100
> 
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -31,6 +31,17 @@
>      equivalent of the CLI's "break -qualified" and "dprintf
>      -qualified".
>  
> +  ** '-file-list-exec-source-files' can now accept a regular
> +     expression for filtering, and accepts the flags --dirname,
> +     --basename and --group-by-binary, making this command equivalent
> +     of the cli 'info sources' command.
> +
> +     In the non '--group-by-binary' mode an extra field
> +     'debug-fully-read' has been added to each source file tuple to
> +     indicate if the debug information for the compilation unit
> +     containing this source file has been fully read or not, the
> +     values for this field are 'true' or 'false'.

This part is OK.

> +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 path
> +to the file.                                           ^^^^^^^^^^^^^
   ^^^^^^^^^^^
GNU Coding Standards frown on calling "path" anything that is not a
PATH-style directory list.  Please use "absolute name of the file"
instead.

>                The @var{fullname} field can be elided if the absolute
> +path to the source file can't be computed.

Likewise.

> +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 source files
> +basename.
   ^^^^^^^^
"basenames", in plural.

> +If @code{--group-by-binary} is used then the format of the results is
> +changed.  The results will now be a list of tuples, with each tuple
> +representing an object file (executable or shared libraries) loaded
> +into @value{GDBN}.  The fields of these tuples are; @var{filename},
> +@var{debug-fully-read}, and @var{sources}.  The @var{filename} is the
> +absolute path to the object file, @var{debug-fully-read} is a string,
   ^^^^^^^^^^^^^
"path" again

Thanks.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 0/4] New option for 'info sources', also better MI support
  2021-04-26 17:06 [PATCH 0/4] New option for 'info sources', also better MI support Andrew Burgess
                   ` (3 preceding siblings ...)
  2021-04-26 17:07 ` [PATCH 4/4] gdb/mi: extend -file-list-exec-source-files command Andrew Burgess
@ 2021-05-13 10:34 ` Andrew Burgess
  2021-05-19 11:12 ` [PATCHv2 0/5] "info sources" - group by objfile Andrew Burgess
  5 siblings, 0 replies; 38+ messages in thread
From: Andrew Burgess @ 2021-05-13 10:34 UTC (permalink / raw)
  To: gdb-patches

Ping!

I know I have some doc feedback that I still need to address, but any
code feedback would be great.

Thanks,
Andrew

* Andrew Burgess <andrew.burgess@embecosm.com> [2021-04-26 18:06:59 +0100]:

> Patches #1 and #2 are setup/cleanup, then...
> 
> patch #2 adds a new option to 'info sources' to get a different view
> on the data, and...
> 
> patch #3 extends the existing MI equivalent of 'info sources' making
> it as powerful as the CLI version.
> 
> ---
> 
> Andrew Burgess (4):
>   gdb: add new function quick_symbol_functions::has_unexpanded_symbols
>   gdb: make struct output_source_filename_data more C++ like
>   gdb: add new -group-by-binary flag to info sources command
>   gdb/mi: extend -file-list-exec-source-files command
> 
>  gdb/ChangeLog                                 |  79 ++++
>  gdb/NEWS                                      |  18 +
>  gdb/doc/ChangeLog                             |  10 +
>  gdb/doc/gdb.texinfo                           | 159 ++++++--
>  gdb/dwarf2/read.c                             |  22 ++
>  gdb/mi/mi-cmd-file.c                          |  84 ++--
>  gdb/objfiles.h                                |   6 +
>  gdb/psympriv.h                                |   2 +
>  gdb/psymtab.c                                 |  18 +
>  gdb/quick-symbol.h                            |   6 +
>  gdb/symfile-debug.c                           |  13 +
>  gdb/symtab.c                                  | 361 ++++++++++++------
>  gdb/symtab.h                                  |  24 ++
>  gdb/testsuite/ChangeLog                       |  16 +
>  gdb/testsuite/gdb.base/info_sources.exp       |   5 +
>  .../gdb.base/info_sources_2-header.h          |  28 ++
>  gdb/testsuite/gdb.base/info_sources_2-lib.c   |  25 ++
>  gdb/testsuite/gdb.base/info_sources_2-test.c  |  26 ++
>  gdb/testsuite/gdb.base/info_sources_2.exp     | 169 ++++++++
>  gdb/testsuite/gdb.dwarf2/dw2-filename.exp     |   2 +-
>  gdb/testsuite/gdb.mi/mi-file.exp              |   2 +-
>  gdb/testsuite/gdb.mi/mi-info-sources-base.c   |  24 ++
>  gdb/testsuite/gdb.mi/mi-info-sources.c        |  25 ++
>  gdb/testsuite/gdb.mi/mi-info-sources.exp      | 177 +++++++++
>  24 files changed, 1127 insertions(+), 174 deletions(-)
>  create mode 100644 gdb/testsuite/gdb.base/info_sources_2-header.h
>  create mode 100644 gdb/testsuite/gdb.base/info_sources_2-lib.c
>  create mode 100644 gdb/testsuite/gdb.base/info_sources_2-test.c
>  create mode 100644 gdb/testsuite/gdb.base/info_sources_2.exp
>  create mode 100644 gdb/testsuite/gdb.mi/mi-info-sources-base.c
>  create mode 100644 gdb/testsuite/gdb.mi/mi-info-sources.c
>  create mode 100644 gdb/testsuite/gdb.mi/mi-info-sources.exp
> 
> -- 
> 2.25.4
> 

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 1/4] gdb: add new function quick_symbol_functions::has_unexpanded_symbols
  2021-04-26 17:07 ` [PATCH 1/4] gdb: add new function quick_symbol_functions::has_unexpanded_symbols Andrew Burgess
@ 2021-05-13 14:38   ` Simon Marchi
  2021-05-13 17:29     ` Tom Tromey
  2021-05-13 14:46   ` Simon Marchi
  1 sibling, 1 reply; 38+ messages in thread
From: Simon Marchi @ 2021-05-13 14:38 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches

> diff --git a/gdb/quick-symbol.h b/gdb/quick-symbol.h
> index f06ceff41c2..096053e75e9 100644
> --- a/gdb/quick-symbol.h
> +++ b/gdb/quick-symbol.h
> @@ -86,6 +86,12 @@ struct quick_symbol_functions
>       available.  */
>    virtual bool has_symbols (struct objfile *objfile) = 0;
>  
> +  /* Return true if OBJFILE has any unexpanded symbols.  A return value of
> +     false indicates there are no unexpanded symbols, this might mean that
> +     all of the symbols have been expanded (full debug has been read in),
> +     or it might been that OBJFILE has no debug information.  */
> +  virtual bool has_unexpanded_symbols (struct objfile *objfile) = 0;

Naming nit: I would maybe suggest to name this "has_unexpanded_symtabs",
since the unit of expansion is a symtab, not a symbol.  I would
understand it better this way.

> diff --git a/gdb/symfile-debug.c b/gdb/symfile-debug.c
> index b839194e2f7..cfc3bed9222 100644
> --- a/gdb/symfile-debug.c
> +++ b/gdb/symfile-debug.c
> @@ -100,6 +100,19 @@ objfile::has_partial_symbols ()
>    return retval;
>  }
>  
> +/* See objfiles.h.  */
> +bool
> +objfile::has_unexpanded_symbols ()
> +{
> +  for (const auto &iter : qf)
> +    {
> +      if (iter->has_unexpanded_symbols (this))
> +	return true;
> +    }
> +
> +  return false;
> +}

I find it odd that this is implemented in this file.  I thought that
symfile-debug.c was just for wrappers that add debug logging.  Maybe
that's how it was back then and it just evolved from there, when
objfiles gained the capability to have multiple symbol providers.

So I think it's fine to add this here, because it's in line with what's
already there, but I would suggest adding the debug logs like there is
in the other functions.

Otherwise, LGTM.

Simon

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 1/4] gdb: add new function quick_symbol_functions::has_unexpanded_symbols
  2021-04-26 17:07 ` [PATCH 1/4] gdb: add new function quick_symbol_functions::has_unexpanded_symbols Andrew Burgess
  2021-05-13 14:38   ` Simon Marchi
@ 2021-05-13 14:46   ` Simon Marchi
  1 sibling, 0 replies; 38+ messages in thread
From: Simon Marchi @ 2021-05-13 14:46 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches

> @@ -4767,6 +4769,26 @@ dwarf2_base_index_functions::has_symbols (struct objfile *objfile)
>    return true;
>  }
>  
> +/* See quick_symbol_functions::has_unexpanded_symbols in quick-symbol.h.  */
> +
> +bool
> +dwarf2_base_index_functions::has_unexpanded_symbols (struct objfile *objfile)
> +{
> +  dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile);
> +
> +  for (dwarf2_per_cu_data *per_cu : per_objfile->per_bfd->all_comp_units)

This will need to be adjusted when rebasing.

Simon

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 2/4] gdb: make struct output_source_filename_data more C++ like
  2021-04-26 17:07 ` [PATCH 2/4] gdb: make struct output_source_filename_data more C++ like Andrew Burgess
@ 2021-05-13 14:58   ` Simon Marchi
  0 siblings, 0 replies; 38+ messages in thread
From: Simon Marchi @ 2021-05-13 14:58 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches

LGTM, I just noted a few nits / potential future cleanups.

> @@ -4211,35 +4212,83 @@ struct filename_partial_match_opts
>    bool basename = false;
>  };
>  
> -/* Data structure to maintain printing state for output_source_filename.  */
> +/* Data structure to maintain the state used for printing the results of
> +   the 'info sources' command.  */
>  
>  struct output_source_filename_data
>  {
> -  /* Output only filenames matching REGEXP.  */
> -  std::string regexp;
> -  gdb::optional<compiled_regex> c_regexp;
> -  /* Possibly only match a part of the filename.  */
> -  filename_partial_match_opts partial_match;
> +  output_source_filename_data (const char *regexp,
> +			       bool match_on_dirname,
> +			       bool match_on_basename)
> +  {
> +    m_partial_match.dirname = match_on_dirname;
> +    m_partial_match.basename = match_on_basename;

You could initialize in in the initializer list:

  : m_partial_match {match_on_dirname, match_on_basename}

>  
> +private:
> +
> +  /* Set the current regular expression, used for matching against files,
> +     to REGEXP.  */
> +  void set_regexp (const std::string regexp)

I'm a bit surprised that this is "const", but gets moved.  I'm
surprised this even compiles at all!

> +  {
> +    m_regexp = std::move (regexp);
> +    if (!m_regexp.empty ())
> +      {
> +	int cflags = REG_NOSUB;
> +#ifdef HAVE_CASE_INSENSITIVE_FILE_SYSTEM
> +	cflags |= REG_ICASE;
> +#endif
> +	m_c_regexp.emplace (m_regexp.c_str (), cflags,
> +			  _("Invalid regexp"));

This last line is missing a bit of indentation.

> +      }
> +  }
> +
> +  /* Output only filenames matching REGEXP.  */
> +  std::string m_regexp;
> +  gdb::optional<compiled_regex> m_c_regexp;
> +
> +  /* Flag of whether we're printing the first one.  */
> +  bool m_first = true;
> +
> +  /* Cache of what we've seen so far.  */
> +  filename_seen_cache m_filename_seen_cache;
> +
> +  /* Possibly only match a part of the filename.  */
> +  filename_partial_match_opts m_partial_match;
>  };
>  
> +/* See comment is class declaration above.  */

is -> in

I'm all for adding comments to functions, but I feel that these comments
(the /* See foo.h.  */ typically) are a bit useless.  If our standard is
to document external functions in headers and class declarations, do we
really need a comment to tell us to go look there for us to go look
there? >/morning rant>

> @@ -4354,49 +4399,33 @@ info_sources_command_completer (cmd_list_element *ignore,
>      return;
>  }
>  
> +/* Implement the 'info sources' command.  */
> +
>  static void
>  info_sources_command (const char *args, int from_tty)
>  {
> -  struct output_source_filename_data data;
> -
>    if (!have_full_symbols () && !have_partial_symbols ())
> -    {
> -      error (_("No symbol table is loaded.  Use the \"file\" command."));
> -    }
> -
> -  filename_seen_cache filenames_seen;
> -
> -  auto group = make_info_sources_options_def_group (&data.partial_match);
> +    error (_("No symbol table is loaded.  Use the \"file\" command."));
>  
> +  struct filename_partial_match_opts match_opts;
> +  auto group = make_info_sources_options_def_group (&match_opts);
>    gdb::option::process_options
>      (&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR, group);
>  
> -  if (args != NULL && *args != '\000')
> -    data.regexp = args;
> +  if (match_opts.dirname && match_opts.basename)
> +    error (_("You cannot give both -basename and -dirname to 'info sources'."));

That's orthogonal to your change, but given that match_on_dirname and
match_on_basename are mutually exclusive, I think that
output_source_filename_data / filename_partial_match_opts should take an
enum instead, like

  enum class match_what
  {
    all,
    dirname,
    basename,
  };

It would be clearer that it's one or the other.  And it would by design
make it impossible for it to have an invalid state (both booleans to
true).

Simon

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 3/4] gdb: add new -group-by-binary flag to info sources command
  2021-04-26 17:07 ` [PATCH 3/4] gdb: add new -group-by-binary flag to info sources command Andrew Burgess
  2021-04-26 17:34   ` Eli Zaretskii
@ 2021-05-13 15:05   ` Simon Marchi
  2021-05-15  8:45     ` Andrew Burgess
  1 sibling, 1 reply; 38+ messages in thread
From: Simon Marchi @ 2021-05-13 15:05 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches

On 2021-04-26 1:07 p.m., Andrew Burgess wrote:
> Currently the 'info sources' command lists all of the known source
> files together, regardless of their source, e.g. here is a session
> debugging a test application that makes use of a shared library:
> 
>   (gdb) info sources
>   Source files for which symbols have been read in:
> 
>   /tmp/info-sources/test.c, /usr/include/stdc-predef.h,
>   /tmp/info-sources/header.h, /tmp/info-sources/helper.c
> 
>   Source files for which symbols will be read in on demand:
> 
>   (gdb)
> 
> In this commit I add a new flag to the 'info sources' command,
> '-group-by-binary'.  When this flag is provided the results are
> grouped by the binary file that uses that source file.  Here's the
> same session using the new flag:
> 
>   (gdb) info sources -group-by-binary
>   /tmp/info-sources/test.x:
> 
>   /tmp/info-sources/test.c, /usr/include/stdc-predef.h,
>   /tmp/info-sources/header.h
> 
>   /lib64/ld-linux-x86-64.so.2:
>   (Full debug information has not yet been read for this file.)
> 
>   system-supplied DSO at 0x7ffff7fcf000:
>   (Full debug information has not yet been read for this file.)
> 
>   /tmp/info-sources/libhelper.so:
> 
>   /tmp/info-sources/helper.c, /usr/include/stdc-predef.h,
>   /tmp/info-sources/header.h
> 
>   /lib64/libc.so.6:
>   (Full debug information has not yet been read for this file.)
> 
>   (gdb)
> 
> Notice that in the new output some source files are repeated,
> e.g. /tmp/info-sources/header.h, as multiple binaries use this source
> file.
> 
> All of the existing regular expression based filtering that exists for
> 'info sources' still works with the new option.

In my opinion the new output is just better, more structured.  Do we
even need to hide it behind an option?  Can we just... change it and
that's it?  I'd lke if we didn't have to keep the extra complexity
unnecessarily.

Simon

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 4/4] gdb/mi: extend -file-list-exec-source-files command
  2021-04-26 17:07 ` [PATCH 4/4] gdb/mi: extend -file-list-exec-source-files command Andrew Burgess
  2021-04-26 17:39   ` Eli Zaretskii
@ 2021-05-13 15:47   ` Simon Marchi
  1 sibling, 0 replies; 38+ messages in thread
From: Simon Marchi @ 2021-05-13 15:47 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches

On 2021-04-26 1:07 p.m., Andrew Burgess wrote:
> This commit extends the -file-list-exec-source-files command to
> support all of the features that the cli 'info sources' supports.
> 
> As this is MI the output of -file-list-exec-source-files should be
> backward compatible, though I have added an extra field into the
> output format, but I believe this is acceptable as a well behaving
> front end is free to ignore a field it doesn't understand.
> 
> As an example, the previous output might look like this:
> 
>   ^done,files=[{file="foo.c",fullname="/home/foo.c"}]
> 
> While the new output would look like:
> 
>   ^done,files=[{file="foo.c",fullname="/home/foo.c",debug-fully-read="true"}]
> 
> With the new field indicating that the source file 'foo.c' is from a
> compilation unit that GDB has fully read in.
> 
> This would allow a front end to recreate GDB's cli output format where
> the source files are split into two groups based on whether the debug
> information for the containing compilation unit has been fully read or
> not.
> 
> While -file-list-exec-source-files previously took no arguments, after
> this commit the command can _optionally_ take some arguments, as these
> are optional this should not break backward compatibility.

Your commit message is missing mentioning the new --group-by-binary
option of the MI command.  It would be useful to have an example with
and without this option, to see the new structure of the output.

In the case of the MI command, it makes sense to have --group-by-binary,
since we need to preserve backwards compatibility.

As Eli said for the doc: I don't know if "binary" is the right term.  I
would tend to say that "object file" is the right term, but it would be
good to check what term we already use elsewhere in the MI and CLI.

But in general the patch looks fine to me.

Simon

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 1/4] gdb: add new function quick_symbol_functions::has_unexpanded_symbols
  2021-05-13 14:38   ` Simon Marchi
@ 2021-05-13 17:29     ` Tom Tromey
  0 siblings, 0 replies; 38+ messages in thread
From: Tom Tromey @ 2021-05-13 17:29 UTC (permalink / raw)
  To: Simon Marchi via Gdb-patches

>>>>> "Simon" == Simon Marchi via Gdb-patches <gdb-patches@sourceware.org> writes:

>> +/* See objfiles.h.  */
>> +bool
>> +objfile::has_unexpanded_symbols ()
>> +{
>> +  for (const auto &iter : qf)
>> +    {
>> +      if (iter->has_unexpanded_symbols (this))
>> +	return true;
>> +    }
>> +
>> +  return false;
>> +}

Simon> I find it odd that this is implemented in this file.  I thought that
Simon> symfile-debug.c was just for wrappers that add debug logging.  Maybe
Simon> that's how it was back then and it just evolved from there, when
Simon> objfiles gained the capability to have multiple symbol providers.

Yeah.

I should probably move it to objfiles.c as you had suggested.

Tom

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 3/4] gdb: add new -group-by-binary flag to info sources command
  2021-05-13 15:05   ` Simon Marchi
@ 2021-05-15  8:45     ` Andrew Burgess
  2021-05-15 13:19       ` Simon Marchi
  0 siblings, 1 reply; 38+ messages in thread
From: Andrew Burgess @ 2021-05-15  8:45 UTC (permalink / raw)
  To: Simon Marchi; +Cc: gdb-patches

* Simon Marchi <simon.marchi@polymtl.ca> [2021-05-13 11:05:44 -0400]:

> On 2021-04-26 1:07 p.m., Andrew Burgess wrote:
> > Currently the 'info sources' command lists all of the known source
> > files together, regardless of their source, e.g. here is a session
> > debugging a test application that makes use of a shared library:
> > 
> >   (gdb) info sources
> >   Source files for which symbols have been read in:
> > 
> >   /tmp/info-sources/test.c, /usr/include/stdc-predef.h,
> >   /tmp/info-sources/header.h, /tmp/info-sources/helper.c
> > 
> >   Source files for which symbols will be read in on demand:
> > 
> >   (gdb)
> > 
> > In this commit I add a new flag to the 'info sources' command,
> > '-group-by-binary'.  When this flag is provided the results are
> > grouped by the binary file that uses that source file.  Here's the
> > same session using the new flag:
> > 
> >   (gdb) info sources -group-by-binary
> >   /tmp/info-sources/test.x:
> > 
> >   /tmp/info-sources/test.c, /usr/include/stdc-predef.h,
> >   /tmp/info-sources/header.h
> > 
> >   /lib64/ld-linux-x86-64.so.2:
> >   (Full debug information has not yet been read for this file.)
> > 
> >   system-supplied DSO at 0x7ffff7fcf000:
> >   (Full debug information has not yet been read for this file.)
> > 
> >   /tmp/info-sources/libhelper.so:
> > 
> >   /tmp/info-sources/helper.c, /usr/include/stdc-predef.h,
> >   /tmp/info-sources/header.h
> > 
> >   /lib64/libc.so.6:
> >   (Full debug information has not yet been read for this file.)
> > 
> >   (gdb)
> > 
> > Notice that in the new output some source files are repeated,
> > e.g. /tmp/info-sources/header.h, as multiple binaries use this source
> > file.
> > 
> > All of the existing regular expression based filtering that exists for
> > 'info sources' still works with the new option.
> 
> In my opinion the new output is just better, more structured.  Do we
> even need to hide it behind an option?  Can we just... change it and
> that's it?  I'd lke if we didn't have to keep the extra complexity
> unnecessarily.

I'm not against changing the output, but I thought as a rule we didn't
significantly change existing command behaviour unless we could show
that the existing behaviour was wrong.

I guess how do folk feel about changing this behaviour?

Thanks,
Andrew


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCH 3/4] gdb: add new -group-by-binary flag to info sources command
  2021-05-15  8:45     ` Andrew Burgess
@ 2021-05-15 13:19       ` Simon Marchi
  0 siblings, 0 replies; 38+ messages in thread
From: Simon Marchi @ 2021-05-15 13:19 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches

On 2021-05-15 4:45 a.m., Andrew Burgess wrote:
> I'm not against changing the output, but I thought as a rule we didn't
> significantly change existing command behaviour unless we could show
> that the existing behaviour was wrong.
>
> I guess how do folk feel about changing this behaviour?

For the CLI, I think we can have a bit of "artistic freedom" to improve
the output, as long as we don't regress use cases.  If we all agree the
new format is better, I would find it disappointing if the fruit of your
work was hidden behind an option, where most people won't know about it
and won't use it.

Simon

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCHv2 0/5] "info sources" - group by objfile
  2021-04-26 17:06 [PATCH 0/4] New option for 'info sources', also better MI support Andrew Burgess
                   ` (4 preceding siblings ...)
  2021-05-13 10:34 ` [PATCH 0/4] New option for 'info sources', also better MI support Andrew Burgess
@ 2021-05-19 11:12 ` Andrew Burgess
  2021-05-19 11:12   ` [PATCHv2 1/5] gdb: add new function quick_symbol_functions::has_unexpanded_symbols Andrew Burgess
                     ` (6 more replies)
  5 siblings, 7 replies; 38+ messages in thread
From: Andrew Burgess @ 2021-05-19 11:12 UTC (permalink / raw)
  To: gdb-patches

Thanks for all the great feedback.

In V2:

 - Documentation talks about object files rather than binaries, I also
   fixed the other doc issues Eli pointed out.

 - Renamed the new quick function in patch #1 to
   has_unexpanded_symtabs as suggested.  The resuling
   objfile::has_unexpanded_symtabs function now has debug print out
   like other quick function wrapper functions.

 - The commit message that adds the new MI option has some example
   output.

 - Instead of adding a new option for CLI "info sources", the output
   format has been changed.

 - Other minor code issues have been cleaned up.

Of note:

 - The new objfile::has_unexpanded_symtabs is still in symfile-debug.c
   rather than objfile.c as Tom suggested.  This ensures that this
   quick function wrapper is in the same source file as all the other
   wrapper functions.  I think we should move all of them together, or
   not at all, and if they do all move it feels like it should be a
   separate, follow-up commit.

Thanks,
Andrew


---

Andrew Burgess (5):
  gdb: add new function quick_symbol_functions::has_unexpanded_symbols
  gdb: make struct output_source_filename_data more C++ like
  gdb/mi: add regexp filtering to -file-list-exec-source-files
  gdb/mi: add new --group-by-objfile flag for
    -file-list-exec-source-files
  gdb: change info sources to group results by objfile

 gdb/ChangeLog                                 | 111 ++++++
 gdb/NEWS                                      |  30 ++
 gdb/doc/ChangeLog                             |  15 +
 gdb/doc/gdb.texinfo                           | 166 +++++++--
 gdb/dwarf2/read.c                             |  22 ++
 gdb/mi/mi-cmd-file.c                          |  92 +++--
 gdb/objfiles.h                                |   6 +
 gdb/psympriv.h                                |   2 +
 gdb/psymtab.c                                 |  18 +
 gdb/quick-symbol.h                            |   6 +
 gdb/symfile-debug.c                           |  25 ++
 gdb/symtab.c                                  | 349 +++++++++++-------
 gdb/symtab.h                                  |  59 +++
 gdb/testsuite/ChangeLog                       |  19 +
 .../gdb.base/info_sources_2-header.h          |  28 ++
 gdb/testsuite/gdb.base/info_sources_2-lib.c   |  25 ++
 gdb/testsuite/gdb.base/info_sources_2-test.c  |  26 ++
 gdb/testsuite/gdb.base/info_sources_2.exp     | 169 +++++++++
 gdb/testsuite/gdb.dwarf2/dw2-filename.exp     |   2 +-
 gdb/testsuite/gdb.mi/mi-file.exp              |   2 +-
 gdb/testsuite/gdb.mi/mi-info-sources-base.c   |  23 ++
 gdb/testsuite/gdb.mi/mi-info-sources.c        |  25 ++
 gdb/testsuite/gdb.mi/mi-info-sources.exp      | 177 +++++++++
 23 files changed, 1205 insertions(+), 192 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/info_sources_2-header.h
 create mode 100644 gdb/testsuite/gdb.base/info_sources_2-lib.c
 create mode 100644 gdb/testsuite/gdb.base/info_sources_2-test.c
 create mode 100644 gdb/testsuite/gdb.base/info_sources_2.exp
 create mode 100644 gdb/testsuite/gdb.mi/mi-info-sources-base.c
 create mode 100644 gdb/testsuite/gdb.mi/mi-info-sources.c
 create mode 100644 gdb/testsuite/gdb.mi/mi-info-sources.exp

-- 
2.25.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCHv2 1/5] gdb: add new function quick_symbol_functions::has_unexpanded_symbols
  2021-05-19 11:12 ` [PATCHv2 0/5] "info sources" - group by objfile Andrew Burgess
@ 2021-05-19 11:12   ` Andrew Burgess
  2021-05-19 11:12   ` [PATCHv2 2/5] gdb: make struct output_source_filename_data more C++ like Andrew Burgess
                     ` (5 subsequent siblings)
  6 siblings, 0 replies; 38+ messages in thread
From: Andrew Burgess @ 2021-05-19 11:12 UTC (permalink / raw)
  To: gdb-patches

Adds a new function to the quick_symbol_functions API to let us know
if there are any unexpanded symbols.  This functionality is required
by a later commit.  After this commit the functionality is unused, and
untested.

The new function objfile::has_unexpanded_symtabs is added to the
symfile-debug.c file which is a little strange, but this
is (currently) where many of the other objfile::* functions (that call
onto the quick_symbol_functions) are defined, so I'm reluctant to
break this pattern.

There should be no user visible changes after this commit.

gdb/ChangeLog:

	* dwarf2/read.c (struct dwarf2_base_index_functions)
	<has_unexpanded_symtabs>: Declare.
	(dwarf2_base_index_functions::has_unexpanded_symtabs): Define new
	function.
	* objfiles.h (struct objfile) <has_unexpanded_symtabs>: Declare.
	* psympriv.h (struct psymbol_functions) <has_unexpanded_symtabs>:
	Declare.
	* psymtab.c (psymbol_functions::has_unexpanded_symtabs): Define
	new function.
	* quick-symbol.h (struct quick_symbol_functions)
	<has_unexpanded_symtabs>: Declare.
	* symfile-debug.c (objfile::has_unexpanded_symtabs): Define new
	function.
---
 gdb/ChangeLog       | 16 ++++++++++++++++
 gdb/dwarf2/read.c   | 22 ++++++++++++++++++++++
 gdb/objfiles.h      |  6 ++++++
 gdb/psympriv.h      |  2 ++
 gdb/psymtab.c       | 18 ++++++++++++++++++
 gdb/quick-symbol.h  |  6 ++++++
 gdb/symfile-debug.c | 25 +++++++++++++++++++++++++
 7 files changed, 95 insertions(+)

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 8a57aeee61c..f7d6332342e 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -2027,6 +2027,8 @@ struct dwarf2_base_index_functions : public quick_symbol_functions
 {
   bool has_symbols (struct objfile *objfile) override;
 
+  bool has_unexpanded_symtabs (struct objfile *objfile) override;
+
   struct symtab *find_last_source_symtab (struct objfile *objfile) override;
 
   void forget_cached_source_info (struct objfile *objfile) override;
@@ -4481,6 +4483,26 @@ dwarf2_base_index_functions::has_symbols (struct objfile *objfile)
   return true;
 }
 
+/* See quick_symbol_functions::has_unexpanded_symtabs in quick-symbol.h.  */
+
+bool
+dwarf2_base_index_functions::has_unexpanded_symtabs (struct objfile *objfile)
+{
+  dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile);
+
+  for (const auto &per_cu : per_objfile->per_bfd->all_comp_units)
+    {
+      /* Is this already expanded?  */
+      if (per_objfile->symtab_set_p (per_cu.get ()))
+	continue;
+
+      /* It has not yet been expanded.  */
+      return true;
+    }
+
+  return false;
+}
+
 /* DWARF-5 debug_names reader.  */
 
 /* DWARF-5 augmentation string for GDB's DW_IDX_GNU_* extension.  */
diff --git a/gdb/objfiles.h b/gdb/objfiles.h
index 5a8a782a646..f947d699132 100644
--- a/gdb/objfiles.h
+++ b/gdb/objfiles.h
@@ -565,6 +565,12 @@ struct objfile
 
   bool has_partial_symbols ();
 
+  /* Return true if this objfile has any unexpanded symbols.  A return
+     value of false indicates either, that this objfile has all its
+     symbols fully expanded (i.e. fully read in), or that this objfile has
+     no symbols at all (i.e. no debug information).  */
+  bool has_unexpanded_symtabs ();
+
   /* See quick_symbol_functions.  */
   struct symtab *find_last_source_symtab ();
 
diff --git a/gdb/psympriv.h b/gdb/psympriv.h
index 59dd66f57e5..3e51b972413 100644
--- a/gdb/psympriv.h
+++ b/gdb/psympriv.h
@@ -503,6 +503,8 @@ struct psymbol_functions : public quick_symbol_functions
 
   bool has_symbols (struct objfile *objfile) override;
 
+  bool has_unexpanded_symtabs (struct objfile *objfile) override;
+
   struct symtab *find_last_source_symtab (struct objfile *objfile) override;
 
   void forget_cached_source_info (struct objfile *objfile) override;
diff --git a/gdb/psymtab.c b/gdb/psymtab.c
index fe32486e2fc..6b8ac010612 100644
--- a/gdb/psymtab.c
+++ b/gdb/psymtab.c
@@ -1184,6 +1184,24 @@ psymbol_functions::has_symbols (struct objfile *objfile)
   return m_partial_symtabs->psymtabs != NULL;
 }
 
+/* See quick_symbol_functions::has_unexpanded_symtabs in quick-symbol.h.  */
+
+bool
+psymbol_functions::has_unexpanded_symtabs (struct objfile *objfile)
+{
+  for (partial_symtab *psymtab : require_partial_symbols (objfile))
+    {
+      /* Is this already expanded?  */
+      if (psymtab->readin_p (objfile))
+	continue;
+
+      /* It has not yet been expanded.  */
+      return true;
+    }
+
+  return false;
+}
+
 /* Helper function for psym_find_compunit_symtab_by_address that fills
    in m_psymbol_map for a given range of psymbols.  */
 
diff --git a/gdb/quick-symbol.h b/gdb/quick-symbol.h
index f06ceff41c2..7af0aebb9fe 100644
--- a/gdb/quick-symbol.h
+++ b/gdb/quick-symbol.h
@@ -86,6 +86,12 @@ struct quick_symbol_functions
      available.  */
   virtual bool has_symbols (struct objfile *objfile) = 0;
 
+  /* Return true if OBJFILE has any unexpanded symtabs.  A return value of
+     false indicates there are no unexpanded symtabs, this might mean that
+     all of the symtabs have been expanded (full debug has been read in),
+     or it might been that OBJFILE has no debug information.  */
+  virtual bool has_unexpanded_symtabs (struct objfile *objfile) = 0;
+
   /* Return the symbol table for the "last" file appearing in
      OBJFILE.  */
   virtual struct symtab *find_last_source_symtab (struct objfile *objfile) = 0;
diff --git a/gdb/symfile-debug.c b/gdb/symfile-debug.c
index b839194e2f7..a10af68f5b1 100644
--- a/gdb/symfile-debug.c
+++ b/gdb/symfile-debug.c
@@ -100,6 +100,31 @@ objfile::has_partial_symbols ()
   return retval;
 }
 
+/* See objfiles.h.  */
+bool
+objfile::has_unexpanded_symtabs ()
+{
+  if (debug_symfile)
+    fprintf_filtered (gdb_stdlog, "qf->has_unexpanded_symtabs (%s)\n",
+		      objfile_debug_name (this));
+
+  bool result = false;
+  for (const auto &iter : qf)
+    {
+      if (iter->has_unexpanded_symtabs (this))
+	{
+	  result = true;
+	  break;
+	}
+    }
+
+  if (debug_symfile)
+    fprintf_filtered (gdb_stdlog, "qf->has_unexpanded_symtabs (%s) = %d\n",
+		      objfile_debug_name (this), (result ? 1 : 0));
+
+  return result;
+}
+
 struct symtab *
 objfile::find_last_source_symtab ()
 {
-- 
2.25.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCHv2 2/5] gdb: make struct output_source_filename_data more C++ like
  2021-05-19 11:12 ` [PATCHv2 0/5] "info sources" - group by objfile Andrew Burgess
  2021-05-19 11:12   ` [PATCHv2 1/5] gdb: add new function quick_symbol_functions::has_unexpanded_symbols Andrew Burgess
@ 2021-05-19 11:12   ` Andrew Burgess
  2021-05-19 11:12   ` [PATCHv2 3/5] gdb/mi: add regexp filtering to -file-list-exec-source-files Andrew Burgess
                     ` (4 subsequent siblings)
  6 siblings, 0 replies; 38+ messages in thread
From: Andrew Burgess @ 2021-05-19 11:12 UTC (permalink / raw)
  To: gdb-patches

In a future commit I'm going to be making some changes to the 'info
sources' command.  While looking at the code I noticed that things
could be improved by making struct output_source_filename_data more
C++ like (private member variables, and more member functions).
That's what this commit does.

The 'info sources' filename filtering is split out into a separate
class in this commit.  In a future commit this new filter
class (info_sources_filter) will move into the header file and be used
from the MI code.

There should be no user visible changes after this commit.

gdb/ChangeLog:

	* symtab.c (struct info_sources_filter): New.
	(info_sources_filter::info_sources_filter): New function.
	(info_sources_filter::matches): New function.
	(info_sources_filter::print): New function.
	(struct filename_partial_match_opts): Moved to later in the file
	and update the comment.
	(struct output_source_filename_data)
	<output_source_filename_data>: New constructor.  <regexp>: Delete,
	this is now in info_sources_filter.  <c_regexp>: Delete, this is
	now in info_sources_filter.  <reset_output>: New member function.
	<filename_seen_cache>: Rename to m_filename_seen_cache, change
	from being a pointer, to being an actual object.  <first>: Rename
	to m_first.  <print_header>: New member function. <partial_match>:
	Delete.
	(output_source_filename_data::output): Update now
	m_filename_seen_cache is no longer a pointer, and for other member
	variable name changes. Add a header comment.
	(print_info_sources_header): Renamed to...
	(output_source_filename_data::print_header): ...this.  Update now
	it's a member function and to take account of member variable
	renaming.
	(info_sources_command): Add a header comment, delete stack local
	filename_seen_cache, initialization of output_source_filename_data
	is now done by the constructor.  Call print_header member function
	instead of print_info_sources_header, call reset_output member
	function instead of manually performing the reset.
---
 gdb/ChangeLog |  29 +++++
 gdb/symtab.c  | 324 +++++++++++++++++++++++++++++++++-----------------
 2 files changed, 247 insertions(+), 106 deletions(-)

diff --git a/gdb/symtab.c b/gdb/symtab.c
index 9555f94707d..c14ab91996e 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4200,46 +4200,190 @@ operator_chars (const char *p, const char **end)
 }
 \f
 
-/* What part to match in a file name.  */
-
-struct filename_partial_match_opts
+/* Class used to encapsulate the filename filtering for the "info sources"
+   command.  */
+struct info_sources_filter
 {
-  /* Only match the directory name part.   */
-  bool dirname = false;
+  /* 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,
 
-  /* Only match the basename part.  */
-  bool basename = false;
+    /* 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;
 };
 
-/* Data structure to maintain printing state for output_source_filename.  */
+/* See class declaration.  */
 
-struct output_source_filename_data
+info_sources_filter::info_sources_filter (match_on match_type,
+                                          const char *regexp)
+  : m_match_type (match_type),
+    m_regexp (regexp)
 {
-  /* Output only filenames matching REGEXP.  */
-  std::string regexp;
-  gdb::optional<compiled_regex> c_regexp;
-  /* Possibly only match a part of the filename.  */
-  filename_partial_match_opts partial_match;
+  /* Setup the compiled regular expression M_C_REGEXP based on M_REGEXP.  */
+  if (m_regexp != nullptr && *m_regexp != '\0')
+    {
+      gdb_assert (m_regexp != nullptr);
 
+      int cflags = REG_NOSUB;
+#ifdef HAVE_CASE_INSENSITIVE_FILE_SYSTEM
+      cflags |= REG_ICASE;
+#endif
+      m_c_regexp.emplace (m_regexp, cflags, _("Invalid regexp"));
+    }
+}
 
-  /* Cache of what we've seen so far.  */
-  struct filename_seen_cache *filename_seen_cache;
+/* See class declaration.  */
 
-  /* Flag of whether we're printing the first one.  */
-  int first;
+bool
+info_sources_filter::matches (const char *fullname) const
+{
+  /* Does it match regexp?  */
+  if (m_c_regexp.has_value ())
+    {
+      const char *to_match;
+      std::string dirname;
+
+      switch (m_match_type)
+        {
+        case match_on::DIRNAME:
+          dirname = ldirname (fullname);
+          to_match = dirname.c_str ();
+          break;
+        case match_on::BASENAME:
+          to_match = lbasename (fullname);
+          break;
+        case match_on::FULLNAME:
+          to_match = fullname;
+          break;
+        }
+
+      if (m_c_regexp->exec (to_match, 0, NULL, 0) != 0)
+        return false;
+    }
+
+  return true;
+}
+
+/* See class declaration.  */
+
+void
+info_sources_filter::print () const
+{
+  if (m_c_regexp.has_value ())
+    {
+      gdb_assert (m_regexp != nullptr);
+
+      switch (m_match_type)
+	{
+	case match_on::DIRNAME:
+	  printf_filtered (_("(dirname matching regular expression \"%s\")"),
+			   m_regexp);
+	  break;
+	case match_on::BASENAME:
+	  printf_filtered (_("(basename matching regular expression \"%s\")"),
+			   m_regexp);
+	  break;
+	case match_on::FULLNAME:
+	  printf_filtered (_("(filename matching regular expression \"%s\")"),
+			   m_regexp);
+	  break;
+	}
+    }
+}
+
+/* Data structure to maintain the state used for printing the results of
+   the 'info sources' command.  */
+
+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)
+  { /* Nothing.  */ }
+
+  DISABLE_COPY_AND_ASSIGN (output_source_filename_data);
+
+  /* Reset enough state of this object so we can match against a new set of
+     files.  The existing regular expression is retained though.  */
+  void reset_output ()
+  {
+    m_first = true;
+    m_filename_seen_cache.clear ();
+  }
 
-  /* Worker for sources_info.  Force line breaks at ,'s.
-     NAME is the name to print.  */
+  /* Worker for sources_info.  Force line breaks at ,'s.  NAME is the name
+     to print.  */
   void output (const char *name);
 
+  /* Prints the header messages for the source files that will be printed
+     with the matching info present in the current object state.
+     SYMBOL_MSG is a message that describes what will or has been done with
+     the symbols of the matching source files.  */
+  void print_header (const char *symbol_msg);
+
   /* An overload suitable for use as a callback to
      quick_symbol_functions::map_symbol_filenames.  */
   void operator() (const char *filename, const char *fullname)
   {
     output (fullname != nullptr ? fullname : filename);
   }
+
+private:
+
+  /* Flag of whether we're printing the first one.  */
+  bool m_first = true;
+
+  /* Cache of what we've seen so far.  */
+  filename_seen_cache m_filename_seen_cache;
+
+  /* How source filename should be filtered.  */
+  const info_sources_filter &m_filter;
 };
 
+/* See comment in class declaration above.  */
+
 void
 output_source_filename_data::output (const char *name)
 {
@@ -4252,42 +4396,45 @@ output_source_filename_data::output (const char *name)
      situation.  I'm not sure whether this can also happen for
      symtabs; it doesn't hurt to check.  */
 
-  /* Was NAME already seen?  */
-  if (filename_seen_cache->seen (name))
-    {
-      /* Yes; don't print it again.  */
-      return;
-    }
-
-  /* Does it match regexp?  */
-  if (c_regexp.has_value ())
-    {
-      const char *to_match;
-      std::string dirname;
-
-      if (partial_match.dirname)
-	{
-	  dirname = ldirname (name);
-	  to_match = dirname.c_str ();
-	}
-      else if (partial_match.basename)
-	to_match = lbasename (name);
-      else
-	to_match = name;
+  /* Was NAME already seen?  If so, then don't print it again.  */
+  if (m_filename_seen_cache.seen (name))
+    return;
 
-      if (c_regexp->exec (to_match, 0, NULL, 0) != 0)
-	return;
-    }
+  /* If the filter rejects this file then don't print it.  */
+  if (!m_filter.matches (name))
+    return;
 
   /* Print it and reset *FIRST.  */
-  if (! first)
+  if (!m_first)
     printf_filtered (", ");
-  first = 0;
+  m_first = false;
 
   wrap_here ("");
   fputs_styled (name, file_name_style.style (), gdb_stdout);
 }
 
+/* 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");
+}
+
+/* For the 'info sources' command, what part of the file names should we be
+   matching the user supplied regular expression against?  */
+
+struct filename_partial_match_opts
+{
+  /* Only match the directory name part.   */
+  bool dirname = false;
+
+  /* Only match the basename part.  */
+  bool basename = false;
+};
+
 using isrc_flag_option_def
   = gdb::option::flag_option_def<filename_partial_match_opts>;
 
@@ -4316,31 +4463,6 @@ make_info_sources_options_def_group (filename_partial_match_opts *isrc_opts)
   return {{info_sources_option_defs}, isrc_opts};
 }
 
-/* Prints the header message for the source files that will be printed
-   with the matching info present in DATA.  SYMBOL_MSG is a message
-   that tells what will or has been done with the symbols of the
-   matching source files.  */
-
-static void
-print_info_sources_header (const char *symbol_msg,
-			   const struct output_source_filename_data *data)
-{
-  puts_filtered (symbol_msg);
-  if (!data->regexp.empty ())
-    {
-      if (data->partial_match.dirname)
-	printf_filtered (_("(dirname matching regular expression \"%s\")"),
-			 data->regexp.c_str ());
-      else if (data->partial_match.basename)
-	printf_filtered (_("(basename matching regular expression \"%s\")"),
-			 data->regexp.c_str ());
-      else
-	printf_filtered (_("(filename matching regular expression \"%s\")"),
-			 data->regexp.c_str ());
-    }
-  puts_filtered ("\n");
-}
-
 /* Completer for "info sources".  */
 
 static void
@@ -4354,49 +4476,41 @@ info_sources_command_completer (cmd_list_element *ignore,
     return;
 }
 
+/* Implement the 'info sources' command.  */
+
 static void
 info_sources_command (const char *args, int from_tty)
 {
-  struct output_source_filename_data data;
-
   if (!have_full_symbols () && !have_partial_symbols ())
-    {
-      error (_("No symbol table is loaded.  Use the \"file\" command."));
-    }
-
-  filename_seen_cache filenames_seen;
-
-  auto group = make_info_sources_options_def_group (&data.partial_match);
+    error (_("No symbol table is loaded.  Use the \"file\" command."));
 
+  filename_partial_match_opts match_opts;
+  auto group = make_info_sources_options_def_group (&match_opts);
   gdb::option::process_options
     (&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR, group);
 
-  if (args != NULL && *args != '\000')
-    data.regexp = args;
+  if (match_opts.dirname && match_opts.basename)
+    error (_("You cannot give both -basename and -dirname to 'info sources'."));
 
-  data.filename_seen_cache = &filenames_seen;
-  data.first = 1;
+  const char *regex = nullptr;
+  if (args != nullptr && *args != '\000')
+    regex = args;
 
-  if (data.partial_match.dirname && data.partial_match.basename)
-    error (_("You cannot give both -basename and -dirname to 'info sources'."));
-  if ((data.partial_match.dirname || data.partial_match.basename)
-      && data.regexp.empty ())
-     error (_("Missing REGEXP for 'info sources'."));
+  if ((match_opts.dirname || match_opts.basename) && regex == nullptr)
+    error (_("Missing REGEXP for 'info sources'."));
 
-  if (data.regexp.empty ())
-    data.c_regexp.reset ();
+  info_sources_filter::match_on match_type;
+  if (match_opts.dirname)
+    match_type = info_sources_filter::match_on::DIRNAME;
+  else if (match_opts.basename)
+    match_type = info_sources_filter::match_on::BASENAME;
   else
-    {
-      int cflags = REG_NOSUB;
-#ifdef HAVE_CASE_INSENSITIVE_FILE_SYSTEM
-      cflags |= REG_ICASE;
-#endif
-      data.c_regexp.emplace (data.regexp.c_str (), cflags,
-			     _("Invalid regexp"));
-    }
+    match_type = info_sources_filter::match_on::FULLNAME;
+
+  info_sources_filter filter (match_type, regex);
+  output_source_filename_data data (filter);
 
-  print_info_sources_header
-    (_("Source files for which symbols have been read in:\n"), &data);
+  data.print_header (_("Source files for which symbols have been read in:\n"));
 
   for (objfile *objfile : current_program_space->objfiles ())
     {
@@ -4412,11 +4526,9 @@ info_sources_command (const char *args, int from_tty)
     }
   printf_filtered ("\n\n");
 
-  print_info_sources_header
-    (_("Source files for which symbols will be read in on demand:\n"), &data);
+  data.print_header (_("Source files for which symbols will be read in on demand:\n"));
 
-  filenames_seen.clear ();
-  data.first = 1;
+  data.reset_output ();
   map_symbol_filenames (data, true /*need_fullname*/);
   printf_filtered ("\n");
 }
-- 
2.25.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCHv2 3/5] gdb/mi: add regexp filtering to -file-list-exec-source-files
  2021-05-19 11:12 ` [PATCHv2 0/5] "info sources" - group by objfile Andrew Burgess
  2021-05-19 11:12   ` [PATCHv2 1/5] gdb: add new function quick_symbol_functions::has_unexpanded_symbols Andrew Burgess
  2021-05-19 11:12   ` [PATCHv2 2/5] gdb: make struct output_source_filename_data more C++ like Andrew Burgess
@ 2021-05-19 11:12   ` Andrew Burgess
  2021-05-19 11:51     ` Eli Zaretskii
  2021-05-19 11:12   ` [PATCHv2 4/5] gdb/mi: add new --group-by-objfile flag for -file-list-exec-source-files Andrew Burgess
                     ` (3 subsequent siblings)
  6 siblings, 1 reply; 38+ messages in thread
From: Andrew Burgess @ 2021-05-19 11:12 UTC (permalink / raw)
  To: gdb-patches

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.
---
 gdb/ChangeLog                               |  27 +++
 gdb/NEWS                                    |  17 ++
 gdb/doc/ChangeLog                           |   5 +
 gdb/doc/gdb.texinfo                         |  74 ++++++--
 gdb/mi/mi-cmd-file.c                        |  86 +++++----
 gdb/symtab.c                                | 190 ++++++++++----------
 gdb/symtab.h                                |  63 +++++++
 gdb/testsuite/ChangeLog                     |   8 +
 gdb/testsuite/gdb.dwarf2/dw2-filename.exp   |   2 +-
 gdb/testsuite/gdb.mi/mi-file.exp            |   2 +-
 gdb/testsuite/gdb.mi/mi-info-sources-base.c |  23 +++
 gdb/testsuite/gdb.mi/mi-info-sources.c      |  25 +++
 gdb/testsuite/gdb.mi/mi-info-sources.exp    | 147 +++++++++++++++
 13 files changed, 520 insertions(+), 149 deletions(-)
 create mode 100644 gdb/testsuite/gdb.mi/mi-info-sources-base.c
 create mode 100644 gdb/testsuite/gdb.mi/mi-info-sources.c
 create mode 100644 gdb/testsuite/gdb.mi/mi-info-sources.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index ab678acec8b..aae0d5b025a 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -46,6 +46,23 @@
     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
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 56f37eb2288..e0789a4b5c6 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -35624,18 +35624,49 @@
 
 
 @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 commands 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.
+
+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
 
@@ -35644,13 +35675,34 @@
 
 @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
diff --git a/gdb/mi/mi-cmd-file.c b/gdb/mi/mi-cmd-file.c
index 430449c919e..684f7eb3f0c 100644
--- a/gdb/mi/mi-cmd-file.c
+++ b/gdb/mi/mi-cmd-file.c
@@ -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.  */
diff --git a/gdb/symtab.c b/gdb/symtab.c
index c14ab91996e..c328b485f3a 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -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 @@ struct output_source_filename_data
 
   /* 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 (_("\
diff --git a/gdb/symtab.h b/gdb/symtab.h
index efdbada9761..7dd659284ed 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -2384,4 +2384,67 @@ class symbol_searcher
   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) */
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-filename.exp b/gdb/testsuite/gdb.dwarf2/dw2-filename.exp
index 3e60f7d2bc9..bd303c8547b 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-filename.exp
+++ b/gdb/testsuite/gdb.dwarf2/dw2-filename.exp
@@ -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.*}
diff --git a/gdb/testsuite/gdb.mi/mi-file.exp b/gdb/testsuite/gdb.mi/mi-file.exp
index 15d7d9f0944..4cae33c017e 100644
--- a/gdb/testsuite/gdb.mi/mi-file.exp
+++ b/gdb/testsuite/gdb.mi/mi-file.exp
@@ -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
index 00000000000..cc736123600
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-info-sources-base.c
@@ -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
index 00000000000..b91b8280c2b
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-info-sources.c
@@ -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
index 00000000000..c218af4ba80
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-info-sources.exp
@@ -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"
-- 
2.25.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCHv2 4/5] gdb/mi: add new --group-by-objfile flag for -file-list-exec-source-files
  2021-05-19 11:12 ` [PATCHv2 0/5] "info sources" - group by objfile Andrew Burgess
                     ` (2 preceding siblings ...)
  2021-05-19 11:12   ` [PATCHv2 3/5] gdb/mi: add regexp filtering to -file-list-exec-source-files Andrew Burgess
@ 2021-05-19 11:12   ` Andrew Burgess
  2021-05-19 11:44     ` Eli Zaretskii
  2021-05-19 11:12   ` [PATCHv2 5/5] gdb: change info sources to group results by objfile Andrew Burgess
                     ` (2 subsequent siblings)
  6 siblings, 1 reply; 38+ messages in thread
From: Andrew Burgess @ 2021-05-19 11:12 UTC (permalink / raw)
  To: gdb-patches

This commit adds a new option '--group-by-objfile' to the MI command
-file-list-exec-source-files.  With this option the output format is
changed; instead of a single list of source files the results are now
a list of objfiles.  For each objfile all of the source files
associated with that objfile are listed.

Here is an example of the new output format taken from the
documentation (the newlines are added just for readability):

  -file-list-exec-source-files --group-by-objfile
  ^done,files=[{filename="/tmp/info-sources/test.x",
                debug-fully-read="true",
                sources=[{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"}]},
               {filename="/lib64/ld-linux-x86-64.so.2",
                debug-fully-read="true",
                sources=[]},
               {filename="system-supplied DSO at 0x7ffff7fcf000",
                debug-fully-read="true",
                sources=[]},
               {filename="/tmp/info-sources/libhelper.so",
                debug-fully-read="true",
                sources=[{file="helper.c",
                          fullname="/tmp/info-sources/helper.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"}]},
               {filename="/lib64/libc.so.6",
                debug-fully-read="true",
                sources=[]}]

In the above output we see, for example, that /lib64/libc.so.6 has had
its debug fully read, but still has no associated source files, this
most likely indicates that libc (in this case) has no debug
information available.

Source files can appear at most once for any single objfile, but can
appear multiple times in total, if the same source file is part of
multiple objfiles, for example /tmp/info-sources/header.h in the above
output.

The new output format is hidden behind a command option to ensure that
the default output is unchanged, this ensures backward compatibility.

The behaviour of the CLI "info sources" command is unchanged after
this commit.

gdb/ChangeLog:

	* NEWS: Mention additions to -file-list-exec-source-files.
	* mi/mi-cmd-file.c (mi_cmd_file_list_exec_source_files): Add
	--group-by-objfile option.
	* symtab.c (isrc_flag_option_def): Rename to...
	(isrc_match_flag_option_def): ...this.
	(info_sources_option_defs): Rename to...
	(info_sources_match_option_defs): ...this, and update to rename of
	isrc_flag_option_def.
	(struct filename_grouping_opts): New struct.
	(isrc_grouping_flag_option_def): New type.
	(info_sources_grouping_option_defs): New static global.
	(make_info_sources_options_def_group): Update to return two option
	groups.
	(info_sources_command_completer): Update for changes to
	make_info_sources_options_def_group.
	(info_sources_worker): Add extra parameter, use this to display
	alternative output format.
	(info_sources_command): Pass extra parameter to
	info_sources_worker.
	(_initialize_symtab): Update for changes to
	make_info_sources_options_def_group.
	* symtab.h (info_sources_worker): Add extra parameter.

gdb/doc/ChangeLog:

	* gdb.texinfo (GDB/MI File Commands): Document --group-by-objfile
	extension for -file-list-exec-source-files.

gdb/testsuite/ChangeLog:

	* gdb.mi/mi-info-sources.exp: Add additional tests.
---
 gdb/ChangeLog                            | 25 ++++++++++++
 gdb/NEWS                                 |  9 ++++-
 gdb/doc/ChangeLog                        |  5 +++
 gdb/doc/gdb.texinfo                      | 48 +++++++++++++++++++++++-
 gdb/mi/mi-cmd-file.c                     | 10 ++++-
 gdb/symtab.c                             | 46 ++++++++++++++++++-----
 gdb/symtab.h                             |  1 +
 gdb/testsuite/ChangeLog                  |  4 ++
 gdb/testsuite/gdb.mi/mi-info-sources.exp | 30 +++++++++++++++
 9 files changed, 165 insertions(+), 13 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index aae0d5b025a..77dd2fac082 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -46,7 +46,9 @@
     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]'
+ ** '-file-list-exec-source-files [--group-by-objfile]
+ 	                          [--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
@@ -56,6 +58,11 @@
     When one of --basename or --dirname is given then REGEXP is only
     matched against the specified part of the full source filename.
 
+    When the optional --group-by-objfile flag is used the output
+    format is changed, the results are now a list of object files
+    (executable and libraries) with the source files that are
+    associated with each object file.
+
     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
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index e0789a4b5c6..692da35f424 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -35630,7 +35630,8 @@
 @subsubheading Synopsis
 
 @smallexample
- -file-list-exec-source-files @r{[} @var{--dirname} @r{|} @var{--basename} @r{]}
+ -file-list-exec-source-files @r{[} @var{--group-by-objfile} @r{]}
+                              @r{[} @var{--dirname} @r{|} @var{--basename} @r{]}
                               @r{[} -- @r{]}
                               @r{[} @var{regexp} @r{]}
 @end smallexample
@@ -35668,6 +35669,19 @@
 source file.  Only one of @code{--dirname} or @code{--basename} may be
 given, and if either is given then @var{regexp} is required.
 
+If @code{--group-by-objfile} is used then the format of the results is
+changed.  The results will now be a list of tuples, with each tuple
+representing an object file (executable or shared libraries) loaded
+into @value{GDBN}.  The fields of these tuples are; @var{filename},
+@var{debug-fully-read}, and @var{sources}.  The @var{filename} is the
+absolute name of the object file, @var{debug-fully-read} is a string,
+either @code{true} or @code{false} indicating if the full debug
+information for this object file has been read in or not.  The
+@var{sources} is a list or tuples, with each tuple describing a single
+source file with the same fields as described previously.  The
+@var{sources} list can be empty for object files that have no debug
+information.
+
 @subsubheading @value{GDBN} Command
 
 The @value{GDBN} equivalent is @samp{info sources}.
@@ -35703,6 +35717,38 @@
               fullname="/tmp/info-sources/helper.c",
               debug-fully-read="true"@}]
 (@value{GDBP})
+-file-list-exec-source-files --group-by-objfile
+^done,files=[@{filename="/tmp/info-sources/test.x",
+              debug-fully-read="true",
+              sources=[@{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"@}]@},
+             @{filename="/lib64/ld-linux-x86-64.so.2",
+              debug-fully-read="true",
+              sources=[]@},
+             @{filename="system-supplied DSO at 0x7ffff7fcf000",
+              debug-fully-read="true",
+              sources=[]@},
+             @{filename="/tmp/info-sources/libhelper.so",
+              debug-fully-read="true",
+              sources=[@{file="helper.c",
+                        fullname="/tmp/info-sources/helper.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"@}]@},
+             @{filename="/lib64/libc.so.6",
+              debug-fully-read="true",
+              sources=[]@}]
 @end smallexample
 
 @subheading The @code{-file-list-shared-libraries} Command
diff --git a/gdb/mi/mi-cmd-file.c b/gdb/mi/mi-cmd-file.c
index 684f7eb3f0c..0970d369cc5 100644
--- a/gdb/mi/mi-cmd-file.c
+++ b/gdb/mi/mi-cmd-file.c
@@ -69,11 +69,13 @@ mi_cmd_file_list_exec_source_files (const char *command, char **argv, int argc)
 {
   enum opt
     {
+      GROUP_BY_OBJFILE_OPT,
       MATCH_BASENAME_OPT,
       MATCH_DIRNAME_OPT
     };
   static const struct mi_opt opts[] =
   {
+    {"-group-by-objfile", GROUP_BY_OBJFILE_OPT, 0},
     {"-basename", MATCH_BASENAME_OPT, 0},
     {"-dirname", MATCH_DIRNAME_OPT, 0},
     { 0, 0, 0 }
@@ -83,6 +85,7 @@ mi_cmd_file_list_exec_source_files (const char *command, char **argv, int argc)
   int oind = 0;
   char *oarg;
 
+  bool group_by_objfile = false;
   bool match_on_basename = false;
   bool match_on_dirname = false;
 
@@ -94,6 +97,9 @@ mi_cmd_file_list_exec_source_files (const char *command, char **argv, int argc)
 	break;
       switch ((enum opt) opt)
 	{
+	case GROUP_BY_OBJFILE_OPT:
+	  group_by_objfile = true;
+	  break;
 	case MATCH_BASENAME_OPT:
 	  match_on_basename = true;
 	  break;
@@ -104,7 +110,7 @@ mi_cmd_file_list_exec_source_files (const char *command, char **argv, int argc)
     }
 
   if ((argc - oind > 1) || (match_on_basename && match_on_dirname))
-    error (_("-file-list-exec-source-files: Usage: [--basename | --dirname] [--] REGEXP"));
+    error (_("-file-list-exec-source-files: Usage: [--group-by-objfile] [--basename | --dirname] [--] REGEXP"));
 
   const char *regexp = nullptr;
   if (argc - oind == 1)
@@ -119,7 +125,7 @@ mi_cmd_file_list_exec_source_files (const char *command, char **argv, int argc)
     match_type = info_sources_filter::match_on::FULLNAME;
 
   info_sources_filter filter (match_type, regexp);
-  info_sources_worker (current_uiout, filter);
+  info_sources_worker (current_uiout, group_by_objfile, filter);
 }
 
 /* See mi-cmds.h.  */
diff --git a/gdb/symtab.c b/gdb/symtab.c
index c328b485f3a..8d75fe4f44c 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4459,6 +4459,7 @@ info_sources_command_completer (cmd_list_element *ignore,
 
 void
 info_sources_worker (struct ui_out *uiout,
+		     bool group_by_objfile,
 		     const info_sources_filter &filter)
 {
   output_source_filename_data data (uiout, filter);
@@ -4467,11 +4468,27 @@ info_sources_worker (struct ui_out *uiout,
   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"));
+  gdb_assert (!group_by_objfile || uiout->is_mi_like_p ());
+
+  if (!group_by_objfile)
+    {
+      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 ())
     {
+      if (group_by_objfile)
+	{
+	  output_tuple.emplace (uiout, nullptr);
+	  uiout->field_string ("filename", objfile_name (objfile));
+	  bool debug_fully_readin = !objfile->has_unexpanded_symtabs ();
+	  current_uiout->field_string ("debug-fully-read",
+				       (debug_fully_readin
+					? "true" : "false"));
+	  sources_list.emplace (uiout, "sources");
+	}
+
       for (compunit_symtab *cu : objfile->compunits ())
 	{
 	  for (symtab *s : compunit_filetabs (cu))
@@ -4481,14 +4498,25 @@ info_sources_worker (struct ui_out *uiout,
 	      data.output (file, fullname, true);
 	    }
 	}
+
+      if (group_by_objfile)
+	{
+	  objfile->map_symbol_filenames (data, true /* need_fullname */);
+	  data.reset_output ();
+	  sources_list.reset ();
+	  output_tuple.reset ();
+	}
     }
 
-  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");
+  if (!group_by_objfile)
+    {
+      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.  */
@@ -4523,7 +4551,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);
-  info_sources_worker (current_uiout, filter);
+  info_sources_worker (current_uiout, false, filter);
 }
 
 /* Compare FILE against all the entries of FILENAMES.  If BASENAMES is
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 7dd659284ed..803b1bc0ce7 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -2445,6 +2445,7 @@ struct info_sources_filter
    Output is written to UIOUT in CLI or MI style as appropriate.  */
 
 extern void info_sources_worker (struct ui_out *uiout,
+				 bool group_by_objfile,
 				 const info_sources_filter &filter);
 
 #endif /* !defined(SYMTAB_H) */
diff --git a/gdb/testsuite/gdb.mi/mi-info-sources.exp b/gdb/testsuite/gdb.mi/mi-info-sources.exp
index c218af4ba80..c7ddcc9aa2f 100644
--- a/gdb/testsuite/gdb.mi/mi-info-sources.exp
+++ b/gdb/testsuite/gdb.mi/mi-info-sources.exp
@@ -137,6 +137,36 @@ proc check_info_sources { debug_fully_read } {
 			[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"
+
+	set p [mi_list "files" \
+		   [mi_tuple "" \
+			[mi_field "filename" "\[^\"\]+/mi-info-sources"] \
+			[mi_field "debug-fully-read" "${debug_fully_read}"] \
+			[mi_list "sources" \
+			     ".*" \
+			     [mi_tuple "" \
+				  [mi_field "file" "\[^\"\]+/mi-info-sources\\.c"] \
+				  [mi_field "fullname" "\[^\"\]+/mi-info-sources\\.c"] \
+				  [mi_field "debug-fully-read" "true"]] \
+			     ".*"]]]
+	mi_gdb_test "-file-list-exec-source-files --group-by-objfile" \
+	    ".*\\^done,${p}" \
+	    "-file-list-exec-source-files --group-by-objfile, look for mi-info-sources.c"
+
+	set p [mi_list "files" \
+		   [mi_tuple "" \
+			[mi_field "filename" "\[^\"\]+/mi-info-sources"] \
+			[mi_field "debug-fully-read" "${debug_fully_read}"] \
+			[mi_list "sources" \
+			     ".*" \
+			     [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 --group-by-objfile" \
+	    ".*\\^done,${p}" \
+	    "-file-list-exec-source-files --group-by-objfile, look for mi-info-sources-base.c"
     }
 }
 
-- 
2.25.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCHv2 5/5] gdb: change info sources to group results by objfile
  2021-05-19 11:12 ` [PATCHv2 0/5] "info sources" - group by objfile Andrew Burgess
                     ` (3 preceding siblings ...)
  2021-05-19 11:12   ` [PATCHv2 4/5] gdb/mi: add new --group-by-objfile flag for -file-list-exec-source-files Andrew Burgess
@ 2021-05-19 11:12   ` Andrew Burgess
  2021-05-19 11:53     ` Eli Zaretskii
  2021-06-03 13:08     ` Simon Marchi
  2021-06-03  9:27   ` [PATCHv2 0/5] "info sources" - group " Andrew Burgess
  2021-06-07 18:32   ` [PATCHv3 " Andrew Burgess
  6 siblings, 2 replies; 38+ messages in thread
From: Andrew Burgess @ 2021-05-19 11:12 UTC (permalink / raw)
  To: gdb-patches

Currently the 'info sources' command lists all of the known source
files together, regardless of their source, e.g. here is a session
debugging a test application that makes use of a shared library:

  (gdb) info sources
  Source files for which symbols have been read in:

  /tmp/info-sources/test.c, /usr/include/stdc-predef.h,
  /tmp/info-sources/header.h, /tmp/info-sources/helper.c

  Source files for which symbols will be read in on demand:

  (gdb)

In this commit I change the format of the 'info sources' results so
that the results are grouped by the object file that uses that source
file.  Here's the same session with the new output format:

  (gdb) info sources
  /tmp/info-sources/test.x:

  /tmp/info-sources/test.c, /usr/include/stdc-predef.h,
  /tmp/info-sources/header.h

  /lib64/ld-linux-x86-64.so.2:
  (Full debug information has not yet been read for this file.)

  system-supplied DSO at 0x7ffff7fcf000:
  (Full debug information has not yet been read for this file.)

  /tmp/info-sources/libhelper.so:

  /tmp/info-sources/helper.c, /usr/include/stdc-predef.h,
  /tmp/info-sources/header.h

  /lib64/libc.so.6:
  (Full debug information has not yet been read for this file.)

  (gdb)

Notice that in the new output some source files are repeated,
e.g. /tmp/info-sources/header.h, as multiple objfiles use this source
file.

All of the existing regular expression based filtering still works.

An original version of this patch added the new format as an option to
'info sources', however, it was felt that the new layout was so much
better than the old style that GDB should just switch to the new
result format completely.

gdb/ChangeLog:

	* NEWS: Mention changes to 'info sources'.
	* symtab.c (info_sources_filter::print): Delete.
	(struct output_source_filename_data) <print_header>: Delete
	declaration.  <printed_filename_p>: New member function.
	(output_source_filename_data::print_header): Delete.
	(info_sources_worker): Update group-by-objfile style output to
	make it CLI suitable, simplify non-group-by-objfile now this is
	only used from the MI.
	(info_sources_command): Make group-by-objfile be the default for
	CLI info sources command.
	* symtab.h (struct info_sources_filter) <print>: Delete.

gdb/doc/ChangeLog:

	* gdb.texinfo (Symbols): Document new output format for 'info
	sources'.

gdb/testsuite/ChangeLog:

	* gdb.base/info_sources_2-header.h: New file.
	* gdb.base/info_sources_2-lib.c: New file.
	* gdb.base/info_sources_2-test.c: New file.
	* gdb.base/info_sources_2.exp: New file.
---
 gdb/ChangeLog                                 |  14 ++
 gdb/NEWS                                      |   6 +
 gdb/doc/ChangeLog                             |   5 +
 gdb/doc/gdb.texinfo                           |  44 +++--
 gdb/symtab.c                                  |  79 +++-----
 gdb/symtab.h                                  |   5 -
 gdb/testsuite/ChangeLog                       |   7 +
 .../gdb.base/info_sources_2-header.h          |  28 +++
 gdb/testsuite/gdb.base/info_sources_2-lib.c   |  25 +++
 gdb/testsuite/gdb.base/info_sources_2-test.c  |  26 +++
 gdb/testsuite/gdb.base/info_sources_2.exp     | 169 ++++++++++++++++++
 11 files changed, 331 insertions(+), 77 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/info_sources_2-header.h
 create mode 100644 gdb/testsuite/gdb.base/info_sources_2-lib.c
 create mode 100644 gdb/testsuite/gdb.base/info_sources_2-test.c
 create mode 100644 gdb/testsuite/gdb.base/info_sources_2.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index 77dd2fac082..712744ba441 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -212,6 +212,12 @@ ptype[/FLAGS] TYPE | EXPRESSION
   offsets of struct members.  Default behavior is given by 'show print
   type hex'.
 
+info sources
+  The info sources command output has been restructured.  The results
+  are now based around a list of objfiles (executable and libraries),
+  and for each objfile the source files that are part of that objfile
+  are listed.
+
 * Removed targets and native configurations
 
 ARM Symbian			arm*-*-symbianelf*
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 692da35f424..ff22faab28f 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -19335,20 +19335,36 @@
 
 
 @kindex info sources
-@item info sources
-Print the names of all source files in your program for which there is
-debugging information, organized into two lists: files whose symbols
-have already been read, and files whose symbols will be read when needed.
-
-@item info sources [-dirname | -basename] [--] [@var{regexp}]
-Like @samp{info sources}, but only print the names of the files
-matching the provided @var{regexp}.
-By default, the @var{regexp} is used to match anywhere in the filename.
-If @code{-dirname}, only files having a dirname matching @var{regexp} are shown.
-If  @code{-basename}, only files having a basename matching @var{regexp}
-are shown.
-The matching is case-sensitive, except on operating systems that
-have case-insensitive filesystem (e.g., MS-Windows).
+@item info sources @r{[}-dirname | -basename@r{]} @r{[}--@r{]} @r{[}@var{regexp}@r{]}
+
+
+With no options @samp{info sources} prints the names of all source
+files in your program for which there is debugging information.  The
+source files are presented based on a list of object files
+(executables and libraries) currently loaded into @value{GDBN}.  For
+each object file all of the associated source files are listed.
+
+Each source file will only be printed once for each object file, but a
+single source file can be repeated in the output if it is part of
+multiple object files.
+
+If the optional @var{regexp} is provided, then only source files that
+match the regular expression will be printed.  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{-}).
+
+By default, the @var{regexp} is used to match anywhere in the
+filename.  If @code{-dirname}, only files having a dirname matching
+@var{regexp} are shown.  If @code{-basename}, only files having a
+basename matching @var{regexp} are shown.
+
+It is possible that an object file may be printed in the list with no
+associated source files.  This can happen when either no source files
+match @var{regexp}, or, the object file was compiled without debug
+information and so @value{GDBN} is unable to find any source file
+names.
 
 @kindex info functions
 @item info functions [-q] [-n]
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 8d75fe4f44c..70793f62a03 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4252,33 +4252,6 @@ info_sources_filter::matches (const char *fullname) const
   return true;
 }
 
-/* See class declaration.  */
-
-void
-info_sources_filter::print (struct ui_out *uiout) const
-{
-  if (m_c_regexp.has_value ())
-    {
-      gdb_assert (m_regexp != nullptr);
-
-      switch (m_match_type)
-	{
-	case match_on::DIRNAME:
-	  uiout->message (_("(dirname matching regular expression \"%s\")"),
-			  m_regexp);
-	  break;
-	case match_on::BASENAME:
-	  uiout->message (_("(basename matching regular expression \"%s\")"),
-			  m_regexp);
-	  break;
-	case match_on::FULLNAME:
-	  printf_filtered (_("(filename matching regular expression \"%s\")"),
-			   m_regexp);
-	  break;
-	}
-    }
-}
-
 /* Data structure to maintain the state used for printing the results of
    the 'info sources' command.  */
 
@@ -4312,12 +4285,6 @@ struct output_source_filename_data
      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.
-     SYMBOL_MSG is a message that describes what will or has been done with
-     the symbols of the matching source files.  */
-  void print_header (const char *symbol_msg);
-
   /* An overload suitable for use as a callback to
      quick_symbol_functions::map_symbol_filenames.  */
   void operator() (const char *filename, const char *fullname)
@@ -4327,6 +4294,14 @@ struct output_source_filename_data
     output (filename, fullname, false);
   }
 
+  /* Return true if at least one filename has been printed (after a call to
+     output) since either this object was created, or the last call to
+     reset_output.  */
+  bool printed_filename_p () const
+  {
+    return !m_first;
+  }
+
 private:
 
   /* Flag of whether we're printing the first one.  */
@@ -4392,16 +4367,6 @@ output_source_filename_data::output (const char *disp_name,
     }
 }
 
-/* See comment is class declaration above.  */
-
-void
-output_source_filename_data::print_header (const char *symbol_msg)
-{
-  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
    matching the user supplied regular expression against?  */
 
@@ -4468,13 +4433,7 @@ info_sources_worker (struct ui_out *uiout,
   gdb::optional<ui_out_emit_tuple> output_tuple;
   gdb::optional<ui_out_emit_list> sources_list;
 
-  gdb_assert (!group_by_objfile || uiout->is_mi_like_p ());
-
-  if (!group_by_objfile)
-    {
-      if (!uiout->is_mi_like_p ())
-	data.print_header (_("Source files for which symbols have been read in:\n"));
-    }
+  gdb_assert (group_by_objfile || uiout->is_mi_like_p ());
 
   for (objfile *objfile : current_program_space->objfiles ())
     {
@@ -4482,10 +4441,16 @@ info_sources_worker (struct ui_out *uiout,
 	{
 	  output_tuple.emplace (uiout, nullptr);
 	  uiout->field_string ("filename", objfile_name (objfile));
+	  uiout->text (":\n");
 	  bool debug_fully_readin = !objfile->has_unexpanded_symtabs ();
-	  current_uiout->field_string ("debug-fully-read",
-				       (debug_fully_readin
-					? "true" : "false"));
+	  if (!debug_fully_readin)
+	    uiout->text ("(Full debug information has not yet been read "
+			 " for this file.)\n");
+	  if (uiout->is_mi_like_p ())
+	    current_uiout->field_string ("debug-fully-read",
+					 (debug_fully_readin
+					  ? "true" : "false"));
+	  uiout->text ("\n");
 	  sources_list.emplace (uiout, "sources");
 	}
 
@@ -4502,6 +4467,8 @@ info_sources_worker (struct ui_out *uiout,
       if (group_by_objfile)
 	{
 	  objfile->map_symbol_filenames (data, true /* need_fullname */);
+	  if (data.printed_filename_p ())
+	    uiout->text ("\n\n");
 	  data.reset_output ();
 	  sources_list.reset ();
 	  output_tuple.reset ();
@@ -4510,12 +4477,8 @@ info_sources_worker (struct ui_out *uiout,
 
   if (!group_by_objfile)
     {
-      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");
     }
 }
 
@@ -4551,7 +4514,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);
-  info_sources_worker (current_uiout, false, filter);
+  info_sources_worker (current_uiout, true, filter);
 }
 
 /* Compare FILE against all the entries of FILENAMES.  If BASENAMES is
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 803b1bc0ce7..160049ab628 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -2419,11 +2419,6 @@ struct info_sources_filter
      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.  */
diff --git a/gdb/testsuite/gdb.base/info_sources_2-header.h b/gdb/testsuite/gdb.base/info_sources_2-header.h
new file mode 100644
index 00000000000..b3379babc0a
--- /dev/null
+++ b/gdb/testsuite/gdb.base/info_sources_2-header.h
@@ -0,0 +1,28 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   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/>.  */
+
+#ifndef INFO_SOURCES_2_HEADER
+#define INFO_SOURCES_2_HEADER
+
+extern int foo (void);
+
+inline static int compare_values (int a, int b)
+{
+  return a == b;
+}
+
+#endif /* INFO_SOURCES_2_HEADER */
diff --git a/gdb/testsuite/gdb.base/info_sources_2-lib.c b/gdb/testsuite/gdb.base/info_sources_2-lib.c
new file mode 100644
index 00000000000..7df1a8114ad
--- /dev/null
+++ b/gdb/testsuite/gdb.base/info_sources_2-lib.c
@@ -0,0 +1,25 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   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/>.  */
+
+
+#include "info_sources_2-header.h"
+
+int
+foo ()
+{
+  return compare_values (0, 1);
+}
diff --git a/gdb/testsuite/gdb.base/info_sources_2-test.c b/gdb/testsuite/gdb.base/info_sources_2-test.c
new file mode 100644
index 00000000000..87a030ae87d
--- /dev/null
+++ b/gdb/testsuite/gdb.base/info_sources_2-test.c
@@ -0,0 +1,26 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   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/>.  */
+
+
+#include "info_sources_2-header.h"
+
+int
+main ()
+{
+  int res = foo ();
+  return compare_values (res, 1);
+}
diff --git a/gdb/testsuite/gdb.base/info_sources_2.exp b/gdb/testsuite/gdb.base/info_sources_2.exp
new file mode 100644
index 00000000000..3aed25b07ac
--- /dev/null
+++ b/gdb/testsuite/gdb.base/info_sources_2.exp
@@ -0,0 +1,169 @@
+# 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 'info sources' when the test file makes use of a shared
+# library.
+
+if { [skip_shlib_tests] } {
+    return 0
+}
+
+standard_testfile -test.c -lib.c
+set solib_name [standard_output_file ${testfile}-lib.so]
+
+if { [gdb_compile_shlib ${srcdir}/${subdir}/${srcfile2} ${solib_name} \
+      {debug}] != "" } {
+    untested "failed to compile shared library"
+    return -1
+}
+
+if {[gdb_compile ${srcdir}/${subdir}/${srcfile} ${binfile} executable \
+     [list debug shlib=${solib_name} ]] != ""} {
+    untested "failed to compile executable"
+    return -1
+}
+
+clean_restart ${binfile}
+
+if ![runto foo] {
+    untested "failed to run to function foo"
+    return -1
+}
+
+# Invoke 'info sources EXTRA_ARGS' and extract the results.
+# The results are then compared to the list ARGS.
+#
+# The list ARGS should consist of pairs of values, the first item being the
+# path to an object file, and the second item being the name of a source file.
+# This proc checks that source file was listed as being a source file for the
+# given object file.
+#
+# If the name of the source file starts with the character "!" (exclamation
+# character, without the quotes) then the check is inverted, that the source
+# file is NOT listed for the given object file.
+proc run_info_sources { extra_args args } {
+    global gdb_prompt srcdir subdir
+
+    with_test_prefix "args: ${extra_args}" {
+
+	# The results of running info sources will be placed into this local.
+	array set info_sources {}
+
+	# The command we are going to run.
+	set cmd "info sources ${extra_args}"
+	set command_regex [string_to_regexp $cmd]
+
+	# Run the command and extract the results into INFO_SOURCES.
+	set objfile_name ""
+	set source_files {}
+	gdb_test_multiple $cmd "" {
+	    -re "${command_regex}\r\n" {
+		exp_continue
+	    }
+
+	    -re "^(\[^\r\n\]+):\r\n" {
+		set objfile_name $expect_out(1,string)
+		exp_continue
+	    }
+
+	    -re "^\\(Full debug information has not yet been read for this file\\.\\)\r\n" {
+		exp_continue
+	    }
+
+	    -re "^\r\n" {
+		exp_continue
+	    }
+
+	    -re "^$gdb_prompt $" {
+		pass $gdb_test_name
+	    }
+
+	    -re "^(\[^\r\n\]+)\r\n" {
+		if { $objfile_name == "" } {
+		    fail "${gdb_test_name} (no objfile name)"
+		    return
+		}
+
+		set files {}
+		foreach f [split $expect_out(1,string) ,] {
+		    lappend files [string trim $f]
+		}
+		set info_sources($objfile_name) $files
+		set $objfile_name ""
+		exp_continue
+	    }
+	}
+
+	# Now check ARGS agaisnt the values held in INFO_SOURCES map.
+	foreach {objfile sourcefile} $args {
+	    # First, figure out if we're expecting SOURCEFILE to be present,
+	    # or not.
+	    set present True
+	    set match_type "is"
+	    if {[string index $sourcefile 0] == "!"} {
+		set present False
+		set match_type "is not"
+		set sourcefile [string range $sourcefile 1 end]
+	    }
+
+	    # Figure out the path for SOURCEFILE that we're looking for.
+	    set sourcepath [file normalize ${srcdir}/${subdir}/${sourcefile}]
+
+	    # Make sure we handle the case where there are no source files
+	    # associated with a particular objfile.
+	    set source_list {}
+	    if [info exists info_sources($objfile)] {
+		set source_list $info_sources($objfile)
+	    }
+
+	    # Now perform the search, and check the results.
+	    set idx [lsearch -exact $source_list $sourcepath]
+	    gdb_assert {($present && $idx >= 0) || (!$present && $idx == -1)} \
+		"source file '$sourcefile' ${match_type} present for '[file tail $objfile]'"
+	}
+    }
+}
+
+# The actual tests.
+
+run_info_sources "" \
+    ${binfile} ${srcfile} \
+    ${binfile} ${testfile}-header.h \
+    ${solib_name} ${srcfile2} \
+    ${solib_name} ${testfile}-header.h
+
+run_info_sources "-basename info_sources_2" \
+    ${binfile} ${srcfile} \
+    ${binfile} ${testfile}-header.h \
+    ${solib_name} ${srcfile2} \
+    ${solib_name} ${testfile}-header.h
+
+run_info_sources "-basename \\.c" \
+    ${binfile} ${srcfile} \
+    ${binfile} !${testfile}-header.h \
+    ${solib_name} ${srcfile2} \
+    ${solib_name} !${testfile}-header.h
+
+run_info_sources "-basename -- -test\\.c" \
+    ${binfile} ${srcfile} \
+    ${binfile} !${testfile}-header.h \
+    ${solib_name} !${srcfile2} \
+    ${solib_name} !${testfile}-header.h
+
+run_info_sources "-basename -- -lib\\.c" \
+    ${binfile} !${srcfile} \
+    ${binfile} !${testfile}-header.h \
+    ${solib_name} ${srcfile2} \
+    ${solib_name} !${testfile}-header.h
-- 
2.25.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCHv2 4/5] gdb/mi: add new --group-by-objfile flag for -file-list-exec-source-files
  2021-05-19 11:12   ` [PATCHv2 4/5] gdb/mi: add new --group-by-objfile flag for -file-list-exec-source-files Andrew Burgess
@ 2021-05-19 11:44     ` Eli Zaretskii
  0 siblings, 0 replies; 38+ messages in thread
From: Eli Zaretskii @ 2021-05-19 11:44 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches

> From: Andrew Burgess <andrew.burgess@embecosm.com>
> Date: Wed, 19 May 2021 12:12:41 +0100
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index aae0d5b025a..77dd2fac082 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -46,7 +46,9 @@
>      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]'
> + ** '-file-list-exec-source-files [--group-by-objfile]
> + 	                          [--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
> @@ -56,6 +58,11 @@
>      When one of --basename or --dirname is given then REGEXP is only
>      matched against the specified part of the full source filename.
>  
> +    When the optional --group-by-objfile flag is used the output
> +    format is changed, the results are now a list of object files
> +    (executable and libraries) with the source files that are
> +    associated with each object file.
> +
>      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

This part is OK.

> +If @code{--group-by-objfile} is used then the format of the results is
> +changed.  The results will now be a list of tuples, with each tuple
> +representing an object file (executable or shared libraries) loaded
                                                     ^^^^^^^^^
"library", in singular.  Other than that, the patch for the manual is
also OK.

Thanks.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCHv2 3/5] gdb/mi: add regexp filtering to -file-list-exec-source-files
  2021-05-19 11:12   ` [PATCHv2 3/5] gdb/mi: add regexp filtering to -file-list-exec-source-files Andrew Burgess
@ 2021-05-19 11:51     ` Eli Zaretskii
  0 siblings, 0 replies; 38+ messages in thread
From: Eli Zaretskii @ 2021-05-19 11:51 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches

> From: Andrew Burgess <andrew.burgess@embecosm.com>
> Date: Wed, 19 May 2021 12:12:40 +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]

Thanks.

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

It is better to make the last sentence of the first paragraph to be
the first sentence of the second paragraph, since these describe the
same aspect of using REGEXP.

> +This commands 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.
               ^^^^^^^^^^^^
I'd suggest to say "is not known to @value{GDBN}", to make the issue
more clear.

> +name of the source file can't be computed. The field
                                            ^^
Two spaces between sentences, please (here and elsewhere).

> +@var{debug-fully-read} will be a string, either @code{true} or
> +@code{false}.  When @code{true} this indicates the full debug
                                  ^
Comma is missing there.

> +information for the compilation unit describing this file has been
> +read in.  When @code{false} the full debug information has not yet
                              ^
And there.

> +@value{GDBN} interpreting @var{regexp} as a command option (e.g. if
> +@var{regexp} starts with @samp{-}).

Please add either a comma or "@:" (without quotes) after "e.g.", so
that TeX won't interpret that as ending a sentence.

> +If @code{--dirname} is provided then @var{regexp} is matched only
                                  ^
Comma missing.

> +against the directory name of each source file.  If @code{--basename}
> +is provided then @var{regexp} is matched against the basename of each
              ^
And here.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCHv2 5/5] gdb: change info sources to group results by objfile
  2021-05-19 11:12   ` [PATCHv2 5/5] gdb: change info sources to group results by objfile Andrew Burgess
@ 2021-05-19 11:53     ` Eli Zaretskii
  2021-06-03 13:08     ` Simon Marchi
  1 sibling, 0 replies; 38+ messages in thread
From: Eli Zaretskii @ 2021-05-19 11:53 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches

> From: Andrew Burgess <andrew.burgess@embecosm.com>
> Date: Wed, 19 May 2021 12:12:42 +0100
> 
> Currently the 'info sources' command lists all of the known source
> files together, regardless of their source, e.g. here is a session
> debugging a test application that makes use of a shared library:
> 
>   (gdb) info sources
>   Source files for which symbols have been read in:
> 
>   /tmp/info-sources/test.c, /usr/include/stdc-predef.h,
>   /tmp/info-sources/header.h, /tmp/info-sources/helper.c
> 
>   Source files for which symbols will be read in on demand:
> 
>   (gdb)
> 
> In this commit I change the format of the 'info sources' results so
> that the results are grouped by the object file that uses that source
> file.  Here's the same session with the new output format:
> 
>   (gdb) info sources
>   /tmp/info-sources/test.x:
> 
>   /tmp/info-sources/test.c, /usr/include/stdc-predef.h,
>   /tmp/info-sources/header.h
> 
>   /lib64/ld-linux-x86-64.so.2:
>   (Full debug information has not yet been read for this file.)
> 
>   system-supplied DSO at 0x7ffff7fcf000:
>   (Full debug information has not yet been read for this file.)
> 
>   /tmp/info-sources/libhelper.so:
> 
>   /tmp/info-sources/helper.c, /usr/include/stdc-predef.h,
>   /tmp/info-sources/header.h
> 
>   /lib64/libc.so.6:
>   (Full debug information has not yet been read for this file.)
> 
>   (gdb)
> 
> Notice that in the new output some source files are repeated,
> e.g. /tmp/info-sources/header.h, as multiple objfiles use this source
> file.
> 
> All of the existing regular expression based filtering still works.
> 
> An original version of this patch added the new format as an option to
> 'info sources', however, it was felt that the new layout was so much
> better than the old style that GDB should just switch to the new
> result format completely.
> 
> gdb/ChangeLog:
> 
> 	* NEWS: Mention changes to 'info sources'.
> 	* symtab.c (info_sources_filter::print): Delete.
> 	(struct output_source_filename_data) <print_header>: Delete
> 	declaration.  <printed_filename_p>: New member function.
> 	(output_source_filename_data::print_header): Delete.
> 	(info_sources_worker): Update group-by-objfile style output to
> 	make it CLI suitable, simplify non-group-by-objfile now this is
> 	only used from the MI.
> 	(info_sources_command): Make group-by-objfile be the default for
> 	CLI info sources command.
> 	* symtab.h (struct info_sources_filter) <print>: Delete.
> 
> gdb/doc/ChangeLog:
> 
> 	* gdb.texinfo (Symbols): Document new output format for 'info
> 	sources'.
> 
> gdb/testsuite/ChangeLog:
> 
> 	* gdb.base/info_sources_2-header.h: New file.
> 	* gdb.base/info_sources_2-lib.c: New file.
> 	* gdb.base/info_sources_2-test.c: New file.
> 	* gdb.base/info_sources_2.exp: New file.

Thanks, the documentation parts are OK.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCHv2 0/5] "info sources" - group by objfile
  2021-05-19 11:12 ` [PATCHv2 0/5] "info sources" - group by objfile Andrew Burgess
                     ` (4 preceding siblings ...)
  2021-05-19 11:12   ` [PATCHv2 5/5] gdb: change info sources to group results by objfile Andrew Burgess
@ 2021-06-03  9:27   ` Andrew Burgess
  2021-06-03 13:15     ` Simon Marchi
  2021-06-07 18:32   ` [PATCHv3 " Andrew Burgess
  6 siblings, 1 reply; 38+ messages in thread
From: Andrew Burgess @ 2021-06-03  9:27 UTC (permalink / raw)
  To: gdb-patches

Ping!

Any thoughts on the new approach?  Specifically, changing the
behaviour of CLI 'info sources'?

Thanks,
Andrew


* Andrew Burgess <andrew.burgess@embecosm.com> [2021-05-19 12:12:37 +0100]:

> Thanks for all the great feedback.
> 
> In V2:
> 
>  - Documentation talks about object files rather than binaries, I also
>    fixed the other doc issues Eli pointed out.
> 
>  - Renamed the new quick function in patch #1 to
>    has_unexpanded_symtabs as suggested.  The resuling
>    objfile::has_unexpanded_symtabs function now has debug print out
>    like other quick function wrapper functions.
> 
>  - The commit message that adds the new MI option has some example
>    output.
> 
>  - Instead of adding a new option for CLI "info sources", the output
>    format has been changed.
> 
>  - Other minor code issues have been cleaned up.
> 
> Of note:
> 
>  - The new objfile::has_unexpanded_symtabs is still in symfile-debug.c
>    rather than objfile.c as Tom suggested.  This ensures that this
>    quick function wrapper is in the same source file as all the other
>    wrapper functions.  I think we should move all of them together, or
>    not at all, and if they do all move it feels like it should be a
>    separate, follow-up commit.
> 
> Thanks,
> Andrew
> 
> 
> ---
> 
> Andrew Burgess (5):
>   gdb: add new function quick_symbol_functions::has_unexpanded_symbols
>   gdb: make struct output_source_filename_data more C++ like
>   gdb/mi: add regexp filtering to -file-list-exec-source-files
>   gdb/mi: add new --group-by-objfile flag for
>     -file-list-exec-source-files
>   gdb: change info sources to group results by objfile
> 
>  gdb/ChangeLog                                 | 111 ++++++
>  gdb/NEWS                                      |  30 ++
>  gdb/doc/ChangeLog                             |  15 +
>  gdb/doc/gdb.texinfo                           | 166 +++++++--
>  gdb/dwarf2/read.c                             |  22 ++
>  gdb/mi/mi-cmd-file.c                          |  92 +++--
>  gdb/objfiles.h                                |   6 +
>  gdb/psympriv.h                                |   2 +
>  gdb/psymtab.c                                 |  18 +
>  gdb/quick-symbol.h                            |   6 +
>  gdb/symfile-debug.c                           |  25 ++
>  gdb/symtab.c                                  | 349 +++++++++++-------
>  gdb/symtab.h                                  |  59 +++
>  gdb/testsuite/ChangeLog                       |  19 +
>  .../gdb.base/info_sources_2-header.h          |  28 ++
>  gdb/testsuite/gdb.base/info_sources_2-lib.c   |  25 ++
>  gdb/testsuite/gdb.base/info_sources_2-test.c  |  26 ++
>  gdb/testsuite/gdb.base/info_sources_2.exp     | 169 +++++++++
>  gdb/testsuite/gdb.dwarf2/dw2-filename.exp     |   2 +-
>  gdb/testsuite/gdb.mi/mi-file.exp              |   2 +-
>  gdb/testsuite/gdb.mi/mi-info-sources-base.c   |  23 ++
>  gdb/testsuite/gdb.mi/mi-info-sources.c        |  25 ++
>  gdb/testsuite/gdb.mi/mi-info-sources.exp      | 177 +++++++++
>  23 files changed, 1205 insertions(+), 192 deletions(-)
>  create mode 100644 gdb/testsuite/gdb.base/info_sources_2-header.h
>  create mode 100644 gdb/testsuite/gdb.base/info_sources_2-lib.c
>  create mode 100644 gdb/testsuite/gdb.base/info_sources_2-test.c
>  create mode 100644 gdb/testsuite/gdb.base/info_sources_2.exp
>  create mode 100644 gdb/testsuite/gdb.mi/mi-info-sources-base.c
>  create mode 100644 gdb/testsuite/gdb.mi/mi-info-sources.c
>  create mode 100644 gdb/testsuite/gdb.mi/mi-info-sources.exp
> 
> -- 
> 2.25.4
> 

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCHv2 5/5] gdb: change info sources to group results by objfile
  2021-05-19 11:12   ` [PATCHv2 5/5] gdb: change info sources to group results by objfile Andrew Burgess
  2021-05-19 11:53     ` Eli Zaretskii
@ 2021-06-03 13:08     ` Simon Marchi
  1 sibling, 0 replies; 38+ messages in thread
From: Simon Marchi @ 2021-06-03 13:08 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches

On 2021-05-19 7:12 a.m., Andrew Burgess wrote:
> @@ -4482,10 +4441,16 @@ info_sources_worker (struct ui_out *uiout,
>  	{
>  	  output_tuple.emplace (uiout, nullptr);
>  	  uiout->field_string ("filename", objfile_name (objfile));
> +	  uiout->text (":\n");
>  	  bool debug_fully_readin = !objfile->has_unexpanded_symtabs ();
> -	  current_uiout->field_string ("debug-fully-read",
> -				       (debug_fully_readin
> -					? "true" : "false"));
> +	  if (!debug_fully_readin)
> +	    uiout->text ("(Full debug information has not yet been read "
> +			 " for this file.)\n");

I just noticed the double space between "read" and "for."

Simon

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCHv2 0/5] "info sources" - group by objfile
  2021-06-03  9:27   ` [PATCHv2 0/5] "info sources" - group " Andrew Burgess
@ 2021-06-03 13:15     ` Simon Marchi
  0 siblings, 0 replies; 38+ messages in thread
From: Simon Marchi @ 2021-06-03 13:15 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches

On 2021-06-03 5:27 a.m., Andrew Burgess wrote:> Any thoughts on the new approach?  Specifically, changing the
> behaviour of CLI 'info sources'?

I already gave my opinion, so I guess you are not waiting for my to
state it again.

But I noticed a little something, here's an excerpt:

    /usr/lib/liblzma.so.5:

    /usr/lib/libbabeltrace.so.1:

    /usr/lib/libbabeltrace-ctf.so.1:

    /usr/lib/libipt.so.2:
    (Full debug information has not yet been read  for this file.)

    /usr/src/debug/libipt-git/libipt/internal/include/pt_section.h, /usr/include/bits/fcntl2.h, /usr/include/sys/stat.h, /usr/include/bits/string_fortified.h, 
    /usr/src/debug/libipt-git/libipt/src/posix/pt_section_posix.c, /usr/include/bits/stdio2.h, /usr/src/debug/libipt-git/include/posix/threads.h, 
    /usr/src/debug/libipt-git/libipt/src/pt_section_file.c, /usr/src/debug/libipt-git/libipt/src/pt_section.c, /usr/src/debug/libipt-git/libipt/internal/include/pt_mapped_section.h, 
    /usr/src/debug/libipt-git/libipt/src/pt_msec_cache.c, /usr/src/debug/libipt-git/libipt/src/pt_block_cache.c, /usr/src/debug/libipt-git/libipt/include/intel-pt.h, 
    /usr/src/debug/libipt-git/libipt/internal/include/pt_block_cache.h, /usr/src/debug/libipt-git/libipt/src/pt_block_decoder.c, /usr/src/debug/libipt-git/libipt/src/pt_insn.c, 
    /usr/src/debug/libipt-git/libipt/src/pt_config.c, /usr/src/debug/libipt-git/libipt/src/pt_decoder_function.c, /usr/src/debug/libipt-git/libipt/src/pt_packet.c, 
    /usr/src/debug/libipt-git/libipt/src/pt_event_queue.c, /usr/src/debug/libipt-git/libipt/src/pt_asid.c, /usr/src/debug/libipt-git/libipt/src/pt_time.c, 
    /usr/src/debug/libipt-git/libipt/src/pt_insn_decoder.c, /usr/src/debug/libipt-git/libipt/src/pt_retstack.c, /usr/src/debug/libipt-git/libipt/src/pt_image_section_cache.c, 
    /usr/src/debug/libipt-git/libipt/src/pt_image.c, /usr/src/debug/libipt-git/libipt/internal/include/pt_ild.h, /usr/src/debug/libipt-git/libipt/src/pt_ild.c, 
    /usr/src/debug/libipt-git/libipt/src/pt_tnt_cache.c, /usr/src/debug/libipt-git/libipt/src/pt_last_ip.c, /usr/src/debug/libipt-git/libipt/src/pt_version.c, 
    /usr/src/debug/libipt-git/libipt/src/pt_sync.c, /usr/src/debug/libipt-git/libipt/src/pt_encoder.c, /usr/src/debug/libipt-git/libipt/src/pt_query_decoder.c, 
    /usr/src/debug/libipt-git/libipt/src/pt_packet_decoder.c, /usr/src/debug/libipt-git/libipt/src/pt_error.c

    /usr/lib/libmpfr.so.6:

Objfiles that have debug info, but not completely read-in, have this
"Full debug information has not yet been read for this file" notice.
But objfiles that have no debug info say nothing.  Should they maybe say
"No debug information available for this file"?

Simon

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCHv3 0/5] "info sources" - group by objfile
  2021-05-19 11:12 ` [PATCHv2 0/5] "info sources" - group by objfile Andrew Burgess
                     ` (5 preceding siblings ...)
  2021-06-03  9:27   ` [PATCHv2 0/5] "info sources" - group " Andrew Burgess
@ 2021-06-07 18:32   ` Andrew Burgess
  2021-06-07 18:32     ` [PATCHv3 1/5] gdb: add new function quick_symbol_functions::has_unexpanded_symbols Andrew Burgess
                       ` (5 more replies)
  6 siblings, 6 replies; 38+ messages in thread
From: Andrew Burgess @ 2021-06-07 18:32 UTC (permalink / raw)
  To: gdb-patches

In V3:

 - 'info sources' now indicates when an objfile has no debug
   information at all, this is a slight change of code, and an update
   to the commit message in patch #5.

 - the MI output is updated to include the same information, there are
   code changes, an update of the commit message, and changes to the
   documentation in patch #4.

 - all the other patches are unchanged.

Thanks,
Andrew


---

Andrew Burgess (5):
  gdb: add new function quick_symbol_functions::has_unexpanded_symbols
  gdb: make struct output_source_filename_data more C++ like
  gdb/mi: add regexp filtering to -file-list-exec-source-files
  gdb/mi: add new --group-by-objfile flag for
    -file-list-exec-source-files
  gdb: change info sources to group results by objfile

 gdb/ChangeLog                                 | 111 ++++++
 gdb/NEWS                                      |  31 ++
 gdb/doc/ChangeLog                             |  15 +
 gdb/doc/gdb.texinfo                           | 176 +++++++--
 gdb/dwarf2/read.c                             |  22 ++
 gdb/mi/mi-cmd-file.c                          |  92 +++--
 gdb/objfiles.h                                |   6 +
 gdb/psympriv.h                                |   2 +
 gdb/psymtab.c                                 |  18 +
 gdb/quick-symbol.h                            |   6 +
 gdb/symfile-debug.c                           |  25 ++
 gdb/symtab.c                                  | 364 ++++++++++++------
 gdb/symtab.h                                  |  59 +++
 gdb/testsuite/ChangeLog                       |  19 +
 .../gdb.base/info_sources_2-header.h          |  28 ++
 gdb/testsuite/gdb.base/info_sources_2-lib.c   |  25 ++
 gdb/testsuite/gdb.base/info_sources_2-test.c  |  26 ++
 gdb/testsuite/gdb.base/info_sources_2.exp     | 169 ++++++++
 gdb/testsuite/gdb.dwarf2/dw2-filename.exp     |   2 +-
 gdb/testsuite/gdb.mi/mi-file.exp              |   2 +-
 gdb/testsuite/gdb.mi/mi-info-sources-base.c   |  23 ++
 gdb/testsuite/gdb.mi/mi-info-sources.c        |  25 ++
 gdb/testsuite/gdb.mi/mi-info-sources.exp      | 184 +++++++++
 23 files changed, 1239 insertions(+), 191 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/info_sources_2-header.h
 create mode 100644 gdb/testsuite/gdb.base/info_sources_2-lib.c
 create mode 100644 gdb/testsuite/gdb.base/info_sources_2-test.c
 create mode 100644 gdb/testsuite/gdb.base/info_sources_2.exp
 create mode 100644 gdb/testsuite/gdb.mi/mi-info-sources-base.c
 create mode 100644 gdb/testsuite/gdb.mi/mi-info-sources.c
 create mode 100644 gdb/testsuite/gdb.mi/mi-info-sources.exp

-- 
2.25.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCHv3 1/5] gdb: add new function quick_symbol_functions::has_unexpanded_symbols
  2021-06-07 18:32   ` [PATCHv3 " Andrew Burgess
@ 2021-06-07 18:32     ` Andrew Burgess
  2021-06-07 18:32     ` [PATCHv3 2/5] gdb: make struct output_source_filename_data more C++ like Andrew Burgess
                       ` (4 subsequent siblings)
  5 siblings, 0 replies; 38+ messages in thread
From: Andrew Burgess @ 2021-06-07 18:32 UTC (permalink / raw)
  To: gdb-patches

Adds a new function to the quick_symbol_functions API to let us know
if there are any unexpanded symbols.  This functionality is required
by a later commit.  After this commit the functionality is unused, and
untested.

The new function objfile::has_unexpanded_symtabs is added to the
symfile-debug.c file which is a little strange, but this
is (currently) where many of the other objfile::* functions (that call
onto the quick_symbol_functions) are defined, so I'm reluctant to
break this pattern.

There should be no user visible changes after this commit.

gdb/ChangeLog:

	* dwarf2/read.c (struct dwarf2_base_index_functions)
	<has_unexpanded_symtabs>: Declare.
	(dwarf2_base_index_functions::has_unexpanded_symtabs): Define new
	function.
	* objfiles.h (struct objfile) <has_unexpanded_symtabs>: Declare.
	* psympriv.h (struct psymbol_functions) <has_unexpanded_symtabs>:
	Declare.
	* psymtab.c (psymbol_functions::has_unexpanded_symtabs): Define
	new function.
	* quick-symbol.h (struct quick_symbol_functions)
	<has_unexpanded_symtabs>: Declare.
	* symfile-debug.c (objfile::has_unexpanded_symtabs): Define new
	function.
---
 gdb/ChangeLog       | 16 ++++++++++++++++
 gdb/dwarf2/read.c   | 22 ++++++++++++++++++++++
 gdb/objfiles.h      |  6 ++++++
 gdb/psympriv.h      |  2 ++
 gdb/psymtab.c       | 18 ++++++++++++++++++
 gdb/quick-symbol.h  |  6 ++++++
 gdb/symfile-debug.c | 25 +++++++++++++++++++++++++
 7 files changed, 95 insertions(+)

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 338003590dc..b0407e6fae7 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -2025,6 +2025,8 @@ struct dwarf2_base_index_functions : public quick_symbol_functions
 {
   bool has_symbols (struct objfile *objfile) override;
 
+  bool has_unexpanded_symtabs (struct objfile *objfile) override;
+
   struct symtab *find_last_source_symtab (struct objfile *objfile) override;
 
   void forget_cached_source_info (struct objfile *objfile) override;
@@ -4477,6 +4479,26 @@ dwarf2_base_index_functions::has_symbols (struct objfile *objfile)
   return true;
 }
 
+/* See quick_symbol_functions::has_unexpanded_symtabs in quick-symbol.h.  */
+
+bool
+dwarf2_base_index_functions::has_unexpanded_symtabs (struct objfile *objfile)
+{
+  dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile);
+
+  for (const auto &per_cu : per_objfile->per_bfd->all_comp_units)
+    {
+      /* Is this already expanded?  */
+      if (per_objfile->symtab_set_p (per_cu.get ()))
+	continue;
+
+      /* It has not yet been expanded.  */
+      return true;
+    }
+
+  return false;
+}
+
 /* DWARF-5 debug_names reader.  */
 
 /* DWARF-5 augmentation string for GDB's DW_IDX_GNU_* extension.  */
diff --git a/gdb/objfiles.h b/gdb/objfiles.h
index 5a8a782a646..f947d699132 100644
--- a/gdb/objfiles.h
+++ b/gdb/objfiles.h
@@ -565,6 +565,12 @@ struct objfile
 
   bool has_partial_symbols ();
 
+  /* Return true if this objfile has any unexpanded symbols.  A return
+     value of false indicates either, that this objfile has all its
+     symbols fully expanded (i.e. fully read in), or that this objfile has
+     no symbols at all (i.e. no debug information).  */
+  bool has_unexpanded_symtabs ();
+
   /* See quick_symbol_functions.  */
   struct symtab *find_last_source_symtab ();
 
diff --git a/gdb/psympriv.h b/gdb/psympriv.h
index 59dd66f57e5..3e51b972413 100644
--- a/gdb/psympriv.h
+++ b/gdb/psympriv.h
@@ -503,6 +503,8 @@ struct psymbol_functions : public quick_symbol_functions
 
   bool has_symbols (struct objfile *objfile) override;
 
+  bool has_unexpanded_symtabs (struct objfile *objfile) override;
+
   struct symtab *find_last_source_symtab (struct objfile *objfile) override;
 
   void forget_cached_source_info (struct objfile *objfile) override;
diff --git a/gdb/psymtab.c b/gdb/psymtab.c
index fe32486e2fc..6b8ac010612 100644
--- a/gdb/psymtab.c
+++ b/gdb/psymtab.c
@@ -1184,6 +1184,24 @@ psymbol_functions::has_symbols (struct objfile *objfile)
   return m_partial_symtabs->psymtabs != NULL;
 }
 
+/* See quick_symbol_functions::has_unexpanded_symtabs in quick-symbol.h.  */
+
+bool
+psymbol_functions::has_unexpanded_symtabs (struct objfile *objfile)
+{
+  for (partial_symtab *psymtab : require_partial_symbols (objfile))
+    {
+      /* Is this already expanded?  */
+      if (psymtab->readin_p (objfile))
+	continue;
+
+      /* It has not yet been expanded.  */
+      return true;
+    }
+
+  return false;
+}
+
 /* Helper function for psym_find_compunit_symtab_by_address that fills
    in m_psymbol_map for a given range of psymbols.  */
 
diff --git a/gdb/quick-symbol.h b/gdb/quick-symbol.h
index f06ceff41c2..7af0aebb9fe 100644
--- a/gdb/quick-symbol.h
+++ b/gdb/quick-symbol.h
@@ -86,6 +86,12 @@ struct quick_symbol_functions
      available.  */
   virtual bool has_symbols (struct objfile *objfile) = 0;
 
+  /* Return true if OBJFILE has any unexpanded symtabs.  A return value of
+     false indicates there are no unexpanded symtabs, this might mean that
+     all of the symtabs have been expanded (full debug has been read in),
+     or it might been that OBJFILE has no debug information.  */
+  virtual bool has_unexpanded_symtabs (struct objfile *objfile) = 0;
+
   /* Return the symbol table for the "last" file appearing in
      OBJFILE.  */
   virtual struct symtab *find_last_source_symtab (struct objfile *objfile) = 0;
diff --git a/gdb/symfile-debug.c b/gdb/symfile-debug.c
index b839194e2f7..a10af68f5b1 100644
--- a/gdb/symfile-debug.c
+++ b/gdb/symfile-debug.c
@@ -100,6 +100,31 @@ objfile::has_partial_symbols ()
   return retval;
 }
 
+/* See objfiles.h.  */
+bool
+objfile::has_unexpanded_symtabs ()
+{
+  if (debug_symfile)
+    fprintf_filtered (gdb_stdlog, "qf->has_unexpanded_symtabs (%s)\n",
+		      objfile_debug_name (this));
+
+  bool result = false;
+  for (const auto &iter : qf)
+    {
+      if (iter->has_unexpanded_symtabs (this))
+	{
+	  result = true;
+	  break;
+	}
+    }
+
+  if (debug_symfile)
+    fprintf_filtered (gdb_stdlog, "qf->has_unexpanded_symtabs (%s) = %d\n",
+		      objfile_debug_name (this), (result ? 1 : 0));
+
+  return result;
+}
+
 struct symtab *
 objfile::find_last_source_symtab ()
 {
-- 
2.25.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCHv3 2/5] gdb: make struct output_source_filename_data more C++ like
  2021-06-07 18:32   ` [PATCHv3 " Andrew Burgess
  2021-06-07 18:32     ` [PATCHv3 1/5] gdb: add new function quick_symbol_functions::has_unexpanded_symbols Andrew Burgess
@ 2021-06-07 18:32     ` Andrew Burgess
  2021-07-05 12:31       ` Tom de Vries
  2021-06-07 18:32     ` [PATCHv3 3/5] gdb/mi: add regexp filtering to -file-list-exec-source-files Andrew Burgess
                       ` (3 subsequent siblings)
  5 siblings, 1 reply; 38+ messages in thread
From: Andrew Burgess @ 2021-06-07 18:32 UTC (permalink / raw)
  To: gdb-patches

In a future commit I'm going to be making some changes to the 'info
sources' command.  While looking at the code I noticed that things
could be improved by making struct output_source_filename_data more
C++ like (private member variables, and more member functions).
That's what this commit does.

The 'info sources' filename filtering is split out into a separate
class in this commit.  In a future commit this new filter
class (info_sources_filter) will move into the header file and be used
from the MI code.

There should be no user visible changes after this commit.

gdb/ChangeLog:

	* symtab.c (struct info_sources_filter): New.
	(info_sources_filter::info_sources_filter): New function.
	(info_sources_filter::matches): New function.
	(info_sources_filter::print): New function.
	(struct filename_partial_match_opts): Moved to later in the file
	and update the comment.
	(struct output_source_filename_data)
	<output_source_filename_data>: New constructor.  <regexp>: Delete,
	this is now in info_sources_filter.  <c_regexp>: Delete, this is
	now in info_sources_filter.  <reset_output>: New member function.
	<filename_seen_cache>: Rename to m_filename_seen_cache, change
	from being a pointer, to being an actual object.  <first>: Rename
	to m_first.  <print_header>: New member function. <partial_match>:
	Delete.
	(output_source_filename_data::output): Update now
	m_filename_seen_cache is no longer a pointer, and for other member
	variable name changes. Add a header comment.
	(print_info_sources_header): Renamed to...
	(output_source_filename_data::print_header): ...this.  Update now
	it's a member function and to take account of member variable
	renaming.
	(info_sources_command): Add a header comment, delete stack local
	filename_seen_cache, initialization of output_source_filename_data
	is now done by the constructor.  Call print_header member function
	instead of print_info_sources_header, call reset_output member
	function instead of manually performing the reset.
---
 gdb/ChangeLog |  29 +++++
 gdb/symtab.c  | 324 +++++++++++++++++++++++++++++++++-----------------
 2 files changed, 247 insertions(+), 106 deletions(-)

diff --git a/gdb/symtab.c b/gdb/symtab.c
index 5ad1c8a817d..2ff79e0cddf 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4200,46 +4200,190 @@ operator_chars (const char *p, const char **end)
 }
 \f
 
-/* What part to match in a file name.  */
-
-struct filename_partial_match_opts
+/* Class used to encapsulate the filename filtering for the "info sources"
+   command.  */
+struct info_sources_filter
 {
-  /* Only match the directory name part.   */
-  bool dirname = false;
+  /* 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,
 
-  /* Only match the basename part.  */
-  bool basename = false;
+    /* 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;
 };
 
-/* Data structure to maintain printing state for output_source_filename.  */
+/* See class declaration.  */
 
-struct output_source_filename_data
+info_sources_filter::info_sources_filter (match_on match_type,
+                                          const char *regexp)
+  : m_match_type (match_type),
+    m_regexp (regexp)
 {
-  /* Output only filenames matching REGEXP.  */
-  std::string regexp;
-  gdb::optional<compiled_regex> c_regexp;
-  /* Possibly only match a part of the filename.  */
-  filename_partial_match_opts partial_match;
+  /* Setup the compiled regular expression M_C_REGEXP based on M_REGEXP.  */
+  if (m_regexp != nullptr && *m_regexp != '\0')
+    {
+      gdb_assert (m_regexp != nullptr);
 
+      int cflags = REG_NOSUB;
+#ifdef HAVE_CASE_INSENSITIVE_FILE_SYSTEM
+      cflags |= REG_ICASE;
+#endif
+      m_c_regexp.emplace (m_regexp, cflags, _("Invalid regexp"));
+    }
+}
 
-  /* Cache of what we've seen so far.  */
-  struct filename_seen_cache *filename_seen_cache;
+/* See class declaration.  */
 
-  /* Flag of whether we're printing the first one.  */
-  int first;
+bool
+info_sources_filter::matches (const char *fullname) const
+{
+  /* Does it match regexp?  */
+  if (m_c_regexp.has_value ())
+    {
+      const char *to_match;
+      std::string dirname;
+
+      switch (m_match_type)
+        {
+        case match_on::DIRNAME:
+          dirname = ldirname (fullname);
+          to_match = dirname.c_str ();
+          break;
+        case match_on::BASENAME:
+          to_match = lbasename (fullname);
+          break;
+        case match_on::FULLNAME:
+          to_match = fullname;
+          break;
+        }
+
+      if (m_c_regexp->exec (to_match, 0, NULL, 0) != 0)
+        return false;
+    }
+
+  return true;
+}
+
+/* See class declaration.  */
+
+void
+info_sources_filter::print () const
+{
+  if (m_c_regexp.has_value ())
+    {
+      gdb_assert (m_regexp != nullptr);
+
+      switch (m_match_type)
+	{
+	case match_on::DIRNAME:
+	  printf_filtered (_("(dirname matching regular expression \"%s\")"),
+			   m_regexp);
+	  break;
+	case match_on::BASENAME:
+	  printf_filtered (_("(basename matching regular expression \"%s\")"),
+			   m_regexp);
+	  break;
+	case match_on::FULLNAME:
+	  printf_filtered (_("(filename matching regular expression \"%s\")"),
+			   m_regexp);
+	  break;
+	}
+    }
+}
+
+/* Data structure to maintain the state used for printing the results of
+   the 'info sources' command.  */
+
+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)
+  { /* Nothing.  */ }
+
+  DISABLE_COPY_AND_ASSIGN (output_source_filename_data);
+
+  /* Reset enough state of this object so we can match against a new set of
+     files.  The existing regular expression is retained though.  */
+  void reset_output ()
+  {
+    m_first = true;
+    m_filename_seen_cache.clear ();
+  }
 
-  /* Worker for sources_info.  Force line breaks at ,'s.
-     NAME is the name to print.  */
+  /* Worker for sources_info.  Force line breaks at ,'s.  NAME is the name
+     to print.  */
   void output (const char *name);
 
+  /* Prints the header messages for the source files that will be printed
+     with the matching info present in the current object state.
+     SYMBOL_MSG is a message that describes what will or has been done with
+     the symbols of the matching source files.  */
+  void print_header (const char *symbol_msg);
+
   /* An overload suitable for use as a callback to
      quick_symbol_functions::map_symbol_filenames.  */
   void operator() (const char *filename, const char *fullname)
   {
     output (fullname != nullptr ? fullname : filename);
   }
+
+private:
+
+  /* Flag of whether we're printing the first one.  */
+  bool m_first = true;
+
+  /* Cache of what we've seen so far.  */
+  filename_seen_cache m_filename_seen_cache;
+
+  /* How source filename should be filtered.  */
+  const info_sources_filter &m_filter;
 };
 
+/* See comment in class declaration above.  */
+
 void
 output_source_filename_data::output (const char *name)
 {
@@ -4252,42 +4396,45 @@ output_source_filename_data::output (const char *name)
      situation.  I'm not sure whether this can also happen for
      symtabs; it doesn't hurt to check.  */
 
-  /* Was NAME already seen?  */
-  if (filename_seen_cache->seen (name))
-    {
-      /* Yes; don't print it again.  */
-      return;
-    }
-
-  /* Does it match regexp?  */
-  if (c_regexp.has_value ())
-    {
-      const char *to_match;
-      std::string dirname;
-
-      if (partial_match.dirname)
-	{
-	  dirname = ldirname (name);
-	  to_match = dirname.c_str ();
-	}
-      else if (partial_match.basename)
-	to_match = lbasename (name);
-      else
-	to_match = name;
+  /* Was NAME already seen?  If so, then don't print it again.  */
+  if (m_filename_seen_cache.seen (name))
+    return;
 
-      if (c_regexp->exec (to_match, 0, NULL, 0) != 0)
-	return;
-    }
+  /* If the filter rejects this file then don't print it.  */
+  if (!m_filter.matches (name))
+    return;
 
   /* Print it and reset *FIRST.  */
-  if (! first)
+  if (!m_first)
     printf_filtered (", ");
-  first = 0;
+  m_first = false;
 
   wrap_here ("");
   fputs_styled (name, file_name_style.style (), gdb_stdout);
 }
 
+/* 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");
+}
+
+/* For the 'info sources' command, what part of the file names should we be
+   matching the user supplied regular expression against?  */
+
+struct filename_partial_match_opts
+{
+  /* Only match the directory name part.   */
+  bool dirname = false;
+
+  /* Only match the basename part.  */
+  bool basename = false;
+};
+
 using isrc_flag_option_def
   = gdb::option::flag_option_def<filename_partial_match_opts>;
 
@@ -4316,31 +4463,6 @@ make_info_sources_options_def_group (filename_partial_match_opts *isrc_opts)
   return {{info_sources_option_defs}, isrc_opts};
 }
 
-/* Prints the header message for the source files that will be printed
-   with the matching info present in DATA.  SYMBOL_MSG is a message
-   that tells what will or has been done with the symbols of the
-   matching source files.  */
-
-static void
-print_info_sources_header (const char *symbol_msg,
-			   const struct output_source_filename_data *data)
-{
-  puts_filtered (symbol_msg);
-  if (!data->regexp.empty ())
-    {
-      if (data->partial_match.dirname)
-	printf_filtered (_("(dirname matching regular expression \"%s\")"),
-			 data->regexp.c_str ());
-      else if (data->partial_match.basename)
-	printf_filtered (_("(basename matching regular expression \"%s\")"),
-			 data->regexp.c_str ());
-      else
-	printf_filtered (_("(filename matching regular expression \"%s\")"),
-			 data->regexp.c_str ());
-    }
-  puts_filtered ("\n");
-}
-
 /* Completer for "info sources".  */
 
 static void
@@ -4354,49 +4476,41 @@ info_sources_command_completer (cmd_list_element *ignore,
     return;
 }
 
+/* Implement the 'info sources' command.  */
+
 static void
 info_sources_command (const char *args, int from_tty)
 {
-  struct output_source_filename_data data;
-
   if (!have_full_symbols () && !have_partial_symbols ())
-    {
-      error (_("No symbol table is loaded.  Use the \"file\" command."));
-    }
-
-  filename_seen_cache filenames_seen;
-
-  auto group = make_info_sources_options_def_group (&data.partial_match);
+    error (_("No symbol table is loaded.  Use the \"file\" command."));
 
+  filename_partial_match_opts match_opts;
+  auto group = make_info_sources_options_def_group (&match_opts);
   gdb::option::process_options
     (&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR, group);
 
-  if (args != NULL && *args != '\000')
-    data.regexp = args;
+  if (match_opts.dirname && match_opts.basename)
+    error (_("You cannot give both -basename and -dirname to 'info sources'."));
 
-  data.filename_seen_cache = &filenames_seen;
-  data.first = 1;
+  const char *regex = nullptr;
+  if (args != nullptr && *args != '\000')
+    regex = args;
 
-  if (data.partial_match.dirname && data.partial_match.basename)
-    error (_("You cannot give both -basename and -dirname to 'info sources'."));
-  if ((data.partial_match.dirname || data.partial_match.basename)
-      && data.regexp.empty ())
-     error (_("Missing REGEXP for 'info sources'."));
+  if ((match_opts.dirname || match_opts.basename) && regex == nullptr)
+    error (_("Missing REGEXP for 'info sources'."));
 
-  if (data.regexp.empty ())
-    data.c_regexp.reset ();
+  info_sources_filter::match_on match_type;
+  if (match_opts.dirname)
+    match_type = info_sources_filter::match_on::DIRNAME;
+  else if (match_opts.basename)
+    match_type = info_sources_filter::match_on::BASENAME;
   else
-    {
-      int cflags = REG_NOSUB;
-#ifdef HAVE_CASE_INSENSITIVE_FILE_SYSTEM
-      cflags |= REG_ICASE;
-#endif
-      data.c_regexp.emplace (data.regexp.c_str (), cflags,
-			     _("Invalid regexp"));
-    }
+    match_type = info_sources_filter::match_on::FULLNAME;
+
+  info_sources_filter filter (match_type, regex);
+  output_source_filename_data data (filter);
 
-  print_info_sources_header
-    (_("Source files for which symbols have been read in:\n"), &data);
+  data.print_header (_("Source files for which symbols have been read in:\n"));
 
   for (objfile *objfile : current_program_space->objfiles ())
     {
@@ -4412,11 +4526,9 @@ info_sources_command (const char *args, int from_tty)
     }
   printf_filtered ("\n\n");
 
-  print_info_sources_header
-    (_("Source files for which symbols will be read in on demand:\n"), &data);
+  data.print_header (_("Source files for which symbols will be read in on demand:\n"));
 
-  filenames_seen.clear ();
-  data.first = 1;
+  data.reset_output ();
   map_symbol_filenames (data, true /*need_fullname*/);
   printf_filtered ("\n");
 }
-- 
2.25.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCHv3 3/5] gdb/mi: add regexp filtering to -file-list-exec-source-files
  2021-06-07 18:32   ` [PATCHv3 " Andrew Burgess
  2021-06-07 18:32     ` [PATCHv3 1/5] gdb: add new function quick_symbol_functions::has_unexpanded_symbols Andrew Burgess
  2021-06-07 18:32     ` [PATCHv3 2/5] gdb: make struct output_source_filename_data more C++ like Andrew Burgess
@ 2021-06-07 18:32     ` Andrew Burgess
  2021-06-07 18:32     ` [PATCHv3 4/5] gdb/mi: add new --group-by-objfile flag for -file-list-exec-source-files Andrew Burgess
                       ` (2 subsequent siblings)
  5 siblings, 0 replies; 38+ messages in thread
From: Andrew Burgess @ 2021-06-07 18:32 UTC (permalink / raw)
  To: gdb-patches

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.
---
 gdb/ChangeLog                               |  27 +++
 gdb/NEWS                                    |  18 ++
 gdb/doc/ChangeLog                           |   5 +
 gdb/doc/gdb.texinfo                         |  74 ++++++--
 gdb/mi/mi-cmd-file.c                        |  86 +++++----
 gdb/symtab.c                                | 190 ++++++++++----------
 gdb/symtab.h                                |  63 +++++++
 gdb/testsuite/ChangeLog                     |   8 +
 gdb/testsuite/gdb.dwarf2/dw2-filename.exp   |   2 +-
 gdb/testsuite/gdb.mi/mi-file.exp            |   2 +-
 gdb/testsuite/gdb.mi/mi-info-sources-base.c |  23 +++
 gdb/testsuite/gdb.mi/mi-info-sources.c      |  25 +++
 gdb/testsuite/gdb.mi/mi-info-sources.exp    | 147 +++++++++++++++
 13 files changed, 521 insertions(+), 149 deletions(-)
 create mode 100644 gdb/testsuite/gdb.mi/mi-info-sources-base.c
 create mode 100644 gdb/testsuite/gdb.mi/mi-info-sources.c
 create mode 100644 gdb/testsuite/gdb.mi/mi-info-sources.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index ab678acec8b..8885c4773a8 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -46,6 +46,24 @@
     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
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 90d827a50e7..af17eb6260f 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -35624,18 +35624,49 @@
 
 
 @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
 
@@ -35644,13 +35675,34 @@
 
 @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
diff --git a/gdb/mi/mi-cmd-file.c b/gdb/mi/mi-cmd-file.c
index 430449c919e..684f7eb3f0c 100644
--- a/gdb/mi/mi-cmd-file.c
+++ b/gdb/mi/mi-cmd-file.c
@@ -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.  */
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 2ff79e0cddf..e300596be6e 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -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 @@ struct output_source_filename_data
 
   /* 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 (_("\
diff --git a/gdb/symtab.h b/gdb/symtab.h
index efdbada9761..7dd659284ed 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -2384,4 +2384,67 @@ class symbol_searcher
   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) */
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-filename.exp b/gdb/testsuite/gdb.dwarf2/dw2-filename.exp
index 3e60f7d2bc9..bd303c8547b 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-filename.exp
+++ b/gdb/testsuite/gdb.dwarf2/dw2-filename.exp
@@ -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.*}
diff --git a/gdb/testsuite/gdb.mi/mi-file.exp b/gdb/testsuite/gdb.mi/mi-file.exp
index 15d7d9f0944..4cae33c017e 100644
--- a/gdb/testsuite/gdb.mi/mi-file.exp
+++ b/gdb/testsuite/gdb.mi/mi-file.exp
@@ -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
index 00000000000..cc736123600
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-info-sources-base.c
@@ -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
index 00000000000..b91b8280c2b
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-info-sources.c
@@ -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
index 00000000000..c218af4ba80
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-info-sources.exp
@@ -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"
-- 
2.25.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCHv3 4/5] gdb/mi: add new --group-by-objfile flag for -file-list-exec-source-files
  2021-06-07 18:32   ` [PATCHv3 " Andrew Burgess
                       ` (2 preceding siblings ...)
  2021-06-07 18:32     ` [PATCHv3 3/5] gdb/mi: add regexp filtering to -file-list-exec-source-files Andrew Burgess
@ 2021-06-07 18:32     ` Andrew Burgess
  2021-06-07 18:32     ` [PATCHv3 5/5] gdb: change info sources to group results by objfile Andrew Burgess
  2021-06-21 12:02     ` PING! Re: [PATCHv3 0/5] "info sources" - group " Andrew Burgess
  5 siblings, 0 replies; 38+ messages in thread
From: Andrew Burgess @ 2021-06-07 18:32 UTC (permalink / raw)
  To: gdb-patches

This commit adds a new option '--group-by-objfile' to the MI command
-file-list-exec-source-files.  With this option the output format is
changed; instead of a single list of source files the results are now
a list of objfiles.  For each objfile all of the source files
associated with that objfile are listed.

Here is an example of the new output format taken from the
documentation (the newlines are added just for readability):

  -file-list-exec-source-files --group-by-objfile
  ^done,files=[{filename="/tmp/info-sources/test.x",
                debug-info="fully-read",
                sources=[{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"}]},
               {filename="/lib64/ld-linux-x86-64.so.2",
                debug-info="none",
                sources=[]},
               {filename="system-supplied DSO at 0x7ffff7fcf000",
                debug-info="none",
                sources=[]},
               {filename="/tmp/info-sources/libhelper.so",
                debug-info="fully-read",
                sources=[{file="helper.c",
                          fullname="/tmp/info-sources/helper.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"}]},
               {filename="/lib64/libc.so.6",
                debug-info="none",
                sources=[]}]

In the above output the 'debug-info' field associated with each
objfile will have one of the values 'none', 'partially-read', or
'fully-read'.  For example, /lib64/libc.so.6 has the value 'none',
this indicates that this object file has no debug information
associated with it, unsurprisingly then, the sources list of this
object file is empty.

An object file that was compiled with debug, for example
/tmp/info-sources/libhelper.so, has the value 'fully-read' above
indicating that this object file does have debug information, and the
information is fully read into GDB.  At different times this field
might have the value 'partially-read' indicating that that the object
file has debug information, but it has not been fully read into GDB
yet.

Source files can appear at most once for any single objfile, but can
appear multiple times in total, if the same source file is part of
multiple objfiles, for example /tmp/info-sources/header.h in the above
output.

The new output format is hidden behind a command option to ensure that
the default output is unchanged, this ensures backward compatibility.

The behaviour of the CLI "info sources" command is unchanged after
this commit.

gdb/ChangeLog:

	* NEWS: Mention additions to -file-list-exec-source-files.
	* mi/mi-cmd-file.c (mi_cmd_file_list_exec_source_files): Add
	--group-by-objfile option.
	* symtab.c (isrc_flag_option_def): Rename to...
	(isrc_match_flag_option_def): ...this.
	(info_sources_option_defs): Rename to...
	(info_sources_match_option_defs): ...this, and update to rename of
	isrc_flag_option_def.
	(struct filename_grouping_opts): New struct.
	(isrc_grouping_flag_option_def): New type.
	(info_sources_grouping_option_defs): New static global.
	(make_info_sources_options_def_group): Update to return two option
	groups.
	(info_sources_command_completer): Update for changes to
	make_info_sources_options_def_group.
	(info_sources_worker): Add extra parameter, use this to display
	alternative output format.
	(info_sources_command): Pass extra parameter to
	info_sources_worker.
	(_initialize_symtab): Update for changes to
	make_info_sources_options_def_group.
	* symtab.h (info_sources_worker): Add extra parameter.

gdb/doc/ChangeLog:

	* gdb.texinfo (GDB/MI File Commands): Document --group-by-objfile
	extension for -file-list-exec-source-files.

gdb/testsuite/ChangeLog:

	* gdb.mi/mi-info-sources.exp: Add additional tests.
---
 gdb/ChangeLog                            | 25 ++++++++++
 gdb/NEWS                                 |  9 +++-
 gdb/doc/ChangeLog                        |  5 ++
 gdb/doc/gdb.texinfo                      | 60 +++++++++++++++++++++++-
 gdb/mi/mi-cmd-file.c                     | 10 +++-
 gdb/symtab.c                             | 54 +++++++++++++++++----
 gdb/symtab.h                             |  1 +
 gdb/testsuite/ChangeLog                  |  4 ++
 gdb/testsuite/gdb.mi/mi-info-sources.exp | 37 +++++++++++++++
 9 files changed, 192 insertions(+), 13 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 8885c4773a8..468d276a939 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -46,7 +46,9 @@
     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]'
+ ** '-file-list-exec-source-files [--group-by-objfile]
+ 	                          [--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
@@ -57,6 +59,11 @@
     REGEXP is only matched against the specified part of the full
     source filename.
 
+    When the optional --group-by-objfile flag is used the output
+    format is changed, the results are now a list of object files
+    (executable and libraries) with the source files that are
+    associated with each object file.
+
     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
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index af17eb6260f..6312a520b7b 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -35630,7 +35630,8 @@
 @subsubheading Synopsis
 
 @smallexample
- -file-list-exec-source-files @r{[} @var{--dirname} @r{|} @var{--basename} @r{]}
+ -file-list-exec-source-files @r{[} @var{--group-by-objfile} @r{]}
+                              @r{[} @var{--dirname} @r{|} @var{--basename} @r{]}
                               @r{[} -- @r{]}
                               @r{[} @var{regexp} @r{]}
 @end smallexample
@@ -35668,6 +35669,31 @@
 source file.  Only one of @code{--dirname} or @code{--basename} may be
 given, and if either is given then @var{regexp} is required.
 
+If @code{--group-by-objfile} is used then the format of the results is
+changed.  The results will now be a list of tuples, with each tuple
+representing an object file (executable or shared library) loaded into
+@value{GDBN}.  The fields of these tuples are; @var{filename},
+@var{debug-info}, and @var{sources}.  The @var{filename} is the
+absolute name of the object file, @var{debug-info} is a string with
+one of the following values:
+
+@table @code
+@item none
+This object file has no debug information.
+@item partially-read
+This object file has debug information, but it is not fully read in
+yet.  When it is read in later, GDB might become aware of additional
+source files.
+@item fully-read
+This object file has debug information, and this information is fully
+read into GDB.  The list of source files is complete.
+@end table
+
+The @var{sources} is a list or tuples, with each tuple describing a
+single source file with the same fields as described previously.  The
+@var{sources} list can be empty for object files that have no debug
+information.
+
 @subsubheading @value{GDBN} Command
 
 The @value{GDBN} equivalent is @samp{info sources}.
@@ -35703,6 +35729,38 @@
               fullname="/tmp/info-sources/helper.c",
               debug-fully-read="true"@}]
 (@value{GDBP})
+-file-list-exec-source-files --group-by-objfile
+^done,files=[@{filename="/tmp/info-sources/test.x",
+              debug-info="fully-read",
+              sources=[@{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"@}]@},
+             @{filename="/lib64/ld-linux-x86-64.so.2",
+              debug-info="none",
+              sources=[]@},
+             @{filename="system-supplied DSO at 0x7ffff7fcf000",
+              debug-info="none",
+              sources=[]@},
+             @{filename="/tmp/info-sources/libhelper.so",
+              debug-info="fully-read",
+              sources=[@{file="helper.c",
+                        fullname="/tmp/info-sources/helper.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"@}]@},
+             @{filename="/lib64/libc.so.6",
+              debug-info="none",
+              sources=[]@}]
 @end smallexample
 
 @subheading The @code{-file-list-shared-libraries} Command
diff --git a/gdb/mi/mi-cmd-file.c b/gdb/mi/mi-cmd-file.c
index 684f7eb3f0c..0970d369cc5 100644
--- a/gdb/mi/mi-cmd-file.c
+++ b/gdb/mi/mi-cmd-file.c
@@ -69,11 +69,13 @@ mi_cmd_file_list_exec_source_files (const char *command, char **argv, int argc)
 {
   enum opt
     {
+      GROUP_BY_OBJFILE_OPT,
       MATCH_BASENAME_OPT,
       MATCH_DIRNAME_OPT
     };
   static const struct mi_opt opts[] =
   {
+    {"-group-by-objfile", GROUP_BY_OBJFILE_OPT, 0},
     {"-basename", MATCH_BASENAME_OPT, 0},
     {"-dirname", MATCH_DIRNAME_OPT, 0},
     { 0, 0, 0 }
@@ -83,6 +85,7 @@ mi_cmd_file_list_exec_source_files (const char *command, char **argv, int argc)
   int oind = 0;
   char *oarg;
 
+  bool group_by_objfile = false;
   bool match_on_basename = false;
   bool match_on_dirname = false;
 
@@ -94,6 +97,9 @@ mi_cmd_file_list_exec_source_files (const char *command, char **argv, int argc)
 	break;
       switch ((enum opt) opt)
 	{
+	case GROUP_BY_OBJFILE_OPT:
+	  group_by_objfile = true;
+	  break;
 	case MATCH_BASENAME_OPT:
 	  match_on_basename = true;
 	  break;
@@ -104,7 +110,7 @@ mi_cmd_file_list_exec_source_files (const char *command, char **argv, int argc)
     }
 
   if ((argc - oind > 1) || (match_on_basename && match_on_dirname))
-    error (_("-file-list-exec-source-files: Usage: [--basename | --dirname] [--] REGEXP"));
+    error (_("-file-list-exec-source-files: Usage: [--group-by-objfile] [--basename | --dirname] [--] REGEXP"));
 
   const char *regexp = nullptr;
   if (argc - oind == 1)
@@ -119,7 +125,7 @@ mi_cmd_file_list_exec_source_files (const char *command, char **argv, int argc)
     match_type = info_sources_filter::match_on::FULLNAME;
 
   info_sources_filter filter (match_type, regexp);
-  info_sources_worker (current_uiout, filter);
+  info_sources_worker (current_uiout, group_by_objfile, filter);
 }
 
 /* See mi-cmds.h.  */
diff --git a/gdb/symtab.c b/gdb/symtab.c
index e300596be6e..cd6da063141 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4459,6 +4459,7 @@ info_sources_command_completer (cmd_list_element *ignore,
 
 void
 info_sources_worker (struct ui_out *uiout,
+		     bool group_by_objfile,
 		     const info_sources_filter &filter)
 {
   output_source_filename_data data (uiout, filter);
@@ -4467,11 +4468,35 @@ info_sources_worker (struct ui_out *uiout,
   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"));
+  gdb_assert (!group_by_objfile || uiout->is_mi_like_p ());
+
+  if (!group_by_objfile)
+    {
+      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 ())
     {
+      if (group_by_objfile)
+	{
+	  output_tuple.emplace (uiout, nullptr);
+	  uiout->field_string ("filename", objfile_name (objfile));
+	  bool debug_fully_readin = !objfile->has_unexpanded_symtabs ();
+	  const char *debug_info_state;
+	  if (objfile_has_symbols (objfile))
+	    {
+	      if (debug_fully_readin)
+		debug_info_state = "fully-read";
+	      else
+		debug_info_state = "partially-read";
+	    }
+	  else
+	    debug_info_state = "none";
+	  current_uiout->field_string ("debug-info", debug_info_state);
+	  sources_list.emplace (uiout, "sources");
+	}
+
       for (compunit_symtab *cu : objfile->compunits ())
 	{
 	  for (symtab *s : compunit_filetabs (cu))
@@ -4481,14 +4506,25 @@ info_sources_worker (struct ui_out *uiout,
 	      data.output (file, fullname, true);
 	    }
 	}
+
+      if (group_by_objfile)
+	{
+	  objfile->map_symbol_filenames (data, true /* need_fullname */);
+	  data.reset_output ();
+	  sources_list.reset ();
+	  output_tuple.reset ();
+	}
     }
 
-  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");
+  if (!group_by_objfile)
+    {
+      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.  */
@@ -4523,7 +4559,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);
-  info_sources_worker (current_uiout, filter);
+  info_sources_worker (current_uiout, false, filter);
 }
 
 /* Compare FILE against all the entries of FILENAMES.  If BASENAMES is
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 7dd659284ed..803b1bc0ce7 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -2445,6 +2445,7 @@ struct info_sources_filter
    Output is written to UIOUT in CLI or MI style as appropriate.  */
 
 extern void info_sources_worker (struct ui_out *uiout,
+				 bool group_by_objfile,
 				 const info_sources_filter &filter);
 
 #endif /* !defined(SYMTAB_H) */
diff --git a/gdb/testsuite/gdb.mi/mi-info-sources.exp b/gdb/testsuite/gdb.mi/mi-info-sources.exp
index c218af4ba80..c4d6b910ef8 100644
--- a/gdb/testsuite/gdb.mi/mi-info-sources.exp
+++ b/gdb/testsuite/gdb.mi/mi-info-sources.exp
@@ -137,6 +137,43 @@ proc check_info_sources { debug_fully_read } {
 			[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"
+
+	# Figure out the value for the 'debug-info' field.
+	if {${debug_fully_read} == "true"} {
+	    set debug_info "fully-read"
+	} else {
+	    set debug_info "partially-read"
+	}
+
+	set p [mi_list "files" \
+		   [mi_tuple "" \
+			[mi_field "filename" "\[^\"\]+/mi-info-sources"] \
+			[mi_field "debug-info" "${debug_info}"] \
+			[mi_list "sources" \
+			     ".*" \
+			     [mi_tuple "" \
+				  [mi_field "file" "\[^\"\]+/mi-info-sources\\.c"] \
+				  [mi_field "fullname" "\[^\"\]+/mi-info-sources\\.c"] \
+				  [mi_field "debug-fully-read" "true"]] \
+			     ".*"]]]
+	mi_gdb_test "-file-list-exec-source-files --group-by-objfile" \
+	    ".*\\^done,${p}" \
+	    "-file-list-exec-source-files --group-by-objfile, look for mi-info-sources.c"
+
+	set p [mi_list "files" \
+		   [mi_tuple "" \
+			[mi_field "filename" "\[^\"\]+/mi-info-sources"] \
+			[mi_field "debug-info" "${debug_info}"] \
+			[mi_list "sources" \
+			     ".*" \
+			     [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 --group-by-objfile" \
+	    ".*\\^done,${p}" \
+	    "-file-list-exec-source-files --group-by-objfile, look for mi-info-sources-base.c"
     }
 }
 
-- 
2.25.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [PATCHv3 5/5] gdb: change info sources to group results by objfile
  2021-06-07 18:32   ` [PATCHv3 " Andrew Burgess
                       ` (3 preceding siblings ...)
  2021-06-07 18:32     ` [PATCHv3 4/5] gdb/mi: add new --group-by-objfile flag for -file-list-exec-source-files Andrew Burgess
@ 2021-06-07 18:32     ` Andrew Burgess
  2021-06-21 12:02     ` PING! Re: [PATCHv3 0/5] "info sources" - group " Andrew Burgess
  5 siblings, 0 replies; 38+ messages in thread
From: Andrew Burgess @ 2021-06-07 18:32 UTC (permalink / raw)
  To: gdb-patches

Currently the 'info sources' command lists all of the known source
files together, regardless of their source, e.g. here is a session
debugging a test application that makes use of a shared library:

  (gdb) info sources
  Source files for which symbols have been read in:

  /tmp/info-sources/test.c, /usr/include/stdc-predef.h,
  /tmp/info-sources/header.h, /tmp/info-sources/helper.c

  Source files for which symbols will be read in on demand:

  (gdb)

In this commit I change the format of the 'info sources' results so
that the results are grouped by the object file that uses that source
file.  Here's the same session with the new output format:

  (gdb) info sources
  /tmp/info-sources/test.x:

  /tmp/info-sources/test.c, /usr/include/stdc-predef.h,
  /tmp/info-sources/header.h

  /lib64/ld-linux-x86-64.so.2:
  (Objfile has no debug information.)

  system-supplied DSO at 0x7ffff7fcf000:
  (Objfile has no debug information.)

  /tmp/info-sources/libhelper.so:

  /tmp/info-sources/helper.c, /usr/include/stdc-predef.h,
  /tmp/info-sources/header.h

  /lib64/libc.so.6:
  (Objfile has no debug information.)

  (gdb)

Notice that in the new output some source files are repeated,
e.g. /tmp/info-sources/header.h, as multiple objfiles use this source
file.

Further, some object files are tagged with the message '(Objfile has
no debug information.)', it is also possible to see the message '(Full
debug information has not yet been read for this file.)', which is
printed when some symtabs within an objfile have not yet been
expanded.

All of the existing regular expression based filtering still works.

An original version of this patch added the new format as an option to
'info sources', however, it was felt that the new layout was so much
better than the old style that GDB should just switch to the new
result format completely.

gdb/ChangeLog:

	* NEWS: Mention changes to 'info sources'.
	* symtab.c (info_sources_filter::print): Delete.
	(struct output_source_filename_data) <print_header>: Delete
	declaration.  <printed_filename_p>: New member function.
	(output_source_filename_data::print_header): Delete.
	(info_sources_worker): Update group-by-objfile style output to
	make it CLI suitable, simplify non-group-by-objfile now this is
	only used from the MI.
	(info_sources_command): Make group-by-objfile be the default for
	CLI info sources command.
	* symtab.h (struct info_sources_filter) <print>: Delete.

gdb/doc/ChangeLog:

	* gdb.texinfo (Symbols): Document new output format for 'info
	sources'.

gdb/testsuite/ChangeLog:

	* gdb.base/info_sources_2-header.h: New file.
	* gdb.base/info_sources_2-lib.c: New file.
	* gdb.base/info_sources_2-test.c: New file.
	* gdb.base/info_sources_2.exp: New file.
---
 gdb/ChangeLog                                 |  14 ++
 gdb/NEWS                                      |   6 +
 gdb/doc/ChangeLog                             |   5 +
 gdb/doc/gdb.texinfo                           |  44 +++--
 gdb/symtab.c                                  |  94 ++++------
 gdb/symtab.h                                  |   5 -
 gdb/testsuite/ChangeLog                       |   7 +
 .../gdb.base/info_sources_2-header.h          |  28 +++
 gdb/testsuite/gdb.base/info_sources_2-lib.c   |  25 +++
 gdb/testsuite/gdb.base/info_sources_2-test.c  |  26 +++
 gdb/testsuite/gdb.base/info_sources_2.exp     | 169 ++++++++++++++++++
 11 files changed, 342 insertions(+), 81 deletions(-)
 create mode 100644 gdb/testsuite/gdb.base/info_sources_2-header.h
 create mode 100644 gdb/testsuite/gdb.base/info_sources_2-lib.c
 create mode 100644 gdb/testsuite/gdb.base/info_sources_2-test.c
 create mode 100644 gdb/testsuite/gdb.base/info_sources_2.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index 468d276a939..fdf0c4de987 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -213,6 +213,12 @@ ptype[/FLAGS] TYPE | EXPRESSION
   offsets of struct members.  Default behavior is given by 'show print
   type hex'.
 
+info sources
+  The info sources command output has been restructured.  The results
+  are now based around a list of objfiles (executable and libraries),
+  and for each objfile the source files that are part of that objfile
+  are listed.
+
 * Removed targets and native configurations
 
 ARM Symbian			arm*-*-symbianelf*
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 6312a520b7b..e574d96dabe 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -19335,20 +19335,36 @@
 
 
 @kindex info sources
-@item info sources
-Print the names of all source files in your program for which there is
-debugging information, organized into two lists: files whose symbols
-have already been read, and files whose symbols will be read when needed.
-
-@item info sources [-dirname | -basename] [--] [@var{regexp}]
-Like @samp{info sources}, but only print the names of the files
-matching the provided @var{regexp}.
-By default, the @var{regexp} is used to match anywhere in the filename.
-If @code{-dirname}, only files having a dirname matching @var{regexp} are shown.
-If  @code{-basename}, only files having a basename matching @var{regexp}
-are shown.
-The matching is case-sensitive, except on operating systems that
-have case-insensitive filesystem (e.g., MS-Windows).
+@item info sources @r{[}-dirname | -basename@r{]} @r{[}--@r{]} @r{[}@var{regexp}@r{]}
+
+
+With no options @samp{info sources} prints the names of all source
+files in your program for which there is debugging information.  The
+source files are presented based on a list of object files
+(executables and libraries) currently loaded into @value{GDBN}.  For
+each object file all of the associated source files are listed.
+
+Each source file will only be printed once for each object file, but a
+single source file can be repeated in the output if it is part of
+multiple object files.
+
+If the optional @var{regexp} is provided, then only source files that
+match the regular expression will be printed.  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{-}).
+
+By default, the @var{regexp} is used to match anywhere in the
+filename.  If @code{-dirname}, only files having a dirname matching
+@var{regexp} are shown.  If @code{-basename}, only files having a
+basename matching @var{regexp} are shown.
+
+It is possible that an object file may be printed in the list with no
+associated source files.  This can happen when either no source files
+match @var{regexp}, or, the object file was compiled without debug
+information and so @value{GDBN} is unable to find any source file
+names.
 
 @kindex info functions
 @item info functions [-q] [-n]
diff --git a/gdb/symtab.c b/gdb/symtab.c
index cd6da063141..7fd037f9701 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -4252,33 +4252,6 @@ info_sources_filter::matches (const char *fullname) const
   return true;
 }
 
-/* See class declaration.  */
-
-void
-info_sources_filter::print (struct ui_out *uiout) const
-{
-  if (m_c_regexp.has_value ())
-    {
-      gdb_assert (m_regexp != nullptr);
-
-      switch (m_match_type)
-	{
-	case match_on::DIRNAME:
-	  uiout->message (_("(dirname matching regular expression \"%s\")"),
-			  m_regexp);
-	  break;
-	case match_on::BASENAME:
-	  uiout->message (_("(basename matching regular expression \"%s\")"),
-			  m_regexp);
-	  break;
-	case match_on::FULLNAME:
-	  printf_filtered (_("(filename matching regular expression \"%s\")"),
-			   m_regexp);
-	  break;
-	}
-    }
-}
-
 /* Data structure to maintain the state used for printing the results of
    the 'info sources' command.  */
 
@@ -4312,12 +4285,6 @@ struct output_source_filename_data
      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.
-     SYMBOL_MSG is a message that describes what will or has been done with
-     the symbols of the matching source files.  */
-  void print_header (const char *symbol_msg);
-
   /* An overload suitable for use as a callback to
      quick_symbol_functions::map_symbol_filenames.  */
   void operator() (const char *filename, const char *fullname)
@@ -4327,6 +4294,14 @@ struct output_source_filename_data
     output (filename, fullname, false);
   }
 
+  /* Return true if at least one filename has been printed (after a call to
+     output) since either this object was created, or the last call to
+     reset_output.  */
+  bool printed_filename_p () const
+  {
+    return !m_first;
+  }
+
 private:
 
   /* Flag of whether we're printing the first one.  */
@@ -4392,16 +4367,6 @@ output_source_filename_data::output (const char *disp_name,
     }
 }
 
-/* See comment is class declaration above.  */
-
-void
-output_source_filename_data::print_header (const char *symbol_msg)
-{
-  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
    matching the user supplied regular expression against?  */
 
@@ -4468,13 +4433,7 @@ info_sources_worker (struct ui_out *uiout,
   gdb::optional<ui_out_emit_tuple> output_tuple;
   gdb::optional<ui_out_emit_list> sources_list;
 
-  gdb_assert (!group_by_objfile || uiout->is_mi_like_p ());
-
-  if (!group_by_objfile)
-    {
-      if (!uiout->is_mi_like_p ())
-	data.print_header (_("Source files for which symbols have been read in:\n"));
-    }
+  gdb_assert (group_by_objfile || uiout->is_mi_like_p ());
 
   for (objfile *objfile : current_program_space->objfiles ())
     {
@@ -4482,18 +4441,31 @@ info_sources_worker (struct ui_out *uiout,
 	{
 	  output_tuple.emplace (uiout, nullptr);
 	  uiout->field_string ("filename", objfile_name (objfile));
+	  uiout->text (":\n");
 	  bool debug_fully_readin = !objfile->has_unexpanded_symtabs ();
-	  const char *debug_info_state;
-	  if (objfile_has_symbols (objfile))
+	  if (uiout->is_mi_like_p ())
 	    {
-	      if (debug_fully_readin)
-		debug_info_state = "fully-read";
+	      const char *debug_info_state;
+	      if (objfile_has_symbols (objfile))
+		{
+		  if (debug_fully_readin)
+		    debug_info_state = "fully-read";
+		  else
+		    debug_info_state = "partially-read";
+		}
 	      else
-		debug_info_state = "partially-read";
+		debug_info_state = "none";
+	      current_uiout->field_string ("debug-info", debug_info_state);
 	    }
 	  else
-	    debug_info_state = "none";
-	  current_uiout->field_string ("debug-info", debug_info_state);
+	    {
+	      if (!debug_fully_readin)
+		uiout->text ("(Full debug information has not yet been read "
+			     "for this file.)\n");
+	      if (!objfile_has_symbols (objfile))
+		uiout->text ("(Objfile has no debug information.)\n");
+	      uiout->text ("\n");
+	    }
 	  sources_list.emplace (uiout, "sources");
 	}
 
@@ -4510,6 +4482,8 @@ info_sources_worker (struct ui_out *uiout,
       if (group_by_objfile)
 	{
 	  objfile->map_symbol_filenames (data, true /* need_fullname */);
+	  if (data.printed_filename_p ())
+	    uiout->text ("\n\n");
 	  data.reset_output ();
 	  sources_list.reset ();
 	  output_tuple.reset ();
@@ -4518,12 +4492,8 @@ info_sources_worker (struct ui_out *uiout,
 
   if (!group_by_objfile)
     {
-      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");
     }
 }
 
@@ -4559,7 +4529,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);
-  info_sources_worker (current_uiout, false, filter);
+  info_sources_worker (current_uiout, true, filter);
 }
 
 /* Compare FILE against all the entries of FILENAMES.  If BASENAMES is
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 803b1bc0ce7..160049ab628 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -2419,11 +2419,6 @@ struct info_sources_filter
      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.  */
diff --git a/gdb/testsuite/gdb.base/info_sources_2-header.h b/gdb/testsuite/gdb.base/info_sources_2-header.h
new file mode 100644
index 00000000000..b3379babc0a
--- /dev/null
+++ b/gdb/testsuite/gdb.base/info_sources_2-header.h
@@ -0,0 +1,28 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   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/>.  */
+
+#ifndef INFO_SOURCES_2_HEADER
+#define INFO_SOURCES_2_HEADER
+
+extern int foo (void);
+
+inline static int compare_values (int a, int b)
+{
+  return a == b;
+}
+
+#endif /* INFO_SOURCES_2_HEADER */
diff --git a/gdb/testsuite/gdb.base/info_sources_2-lib.c b/gdb/testsuite/gdb.base/info_sources_2-lib.c
new file mode 100644
index 00000000000..7df1a8114ad
--- /dev/null
+++ b/gdb/testsuite/gdb.base/info_sources_2-lib.c
@@ -0,0 +1,25 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   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/>.  */
+
+
+#include "info_sources_2-header.h"
+
+int
+foo ()
+{
+  return compare_values (0, 1);
+}
diff --git a/gdb/testsuite/gdb.base/info_sources_2-test.c b/gdb/testsuite/gdb.base/info_sources_2-test.c
new file mode 100644
index 00000000000..87a030ae87d
--- /dev/null
+++ b/gdb/testsuite/gdb.base/info_sources_2-test.c
@@ -0,0 +1,26 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   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/>.  */
+
+
+#include "info_sources_2-header.h"
+
+int
+main ()
+{
+  int res = foo ();
+  return compare_values (res, 1);
+}
diff --git a/gdb/testsuite/gdb.base/info_sources_2.exp b/gdb/testsuite/gdb.base/info_sources_2.exp
new file mode 100644
index 00000000000..3aed25b07ac
--- /dev/null
+++ b/gdb/testsuite/gdb.base/info_sources_2.exp
@@ -0,0 +1,169 @@
+# 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 'info sources' when the test file makes use of a shared
+# library.
+
+if { [skip_shlib_tests] } {
+    return 0
+}
+
+standard_testfile -test.c -lib.c
+set solib_name [standard_output_file ${testfile}-lib.so]
+
+if { [gdb_compile_shlib ${srcdir}/${subdir}/${srcfile2} ${solib_name} \
+      {debug}] != "" } {
+    untested "failed to compile shared library"
+    return -1
+}
+
+if {[gdb_compile ${srcdir}/${subdir}/${srcfile} ${binfile} executable \
+     [list debug shlib=${solib_name} ]] != ""} {
+    untested "failed to compile executable"
+    return -1
+}
+
+clean_restart ${binfile}
+
+if ![runto foo] {
+    untested "failed to run to function foo"
+    return -1
+}
+
+# Invoke 'info sources EXTRA_ARGS' and extract the results.
+# The results are then compared to the list ARGS.
+#
+# The list ARGS should consist of pairs of values, the first item being the
+# path to an object file, and the second item being the name of a source file.
+# This proc checks that source file was listed as being a source file for the
+# given object file.
+#
+# If the name of the source file starts with the character "!" (exclamation
+# character, without the quotes) then the check is inverted, that the source
+# file is NOT listed for the given object file.
+proc run_info_sources { extra_args args } {
+    global gdb_prompt srcdir subdir
+
+    with_test_prefix "args: ${extra_args}" {
+
+	# The results of running info sources will be placed into this local.
+	array set info_sources {}
+
+	# The command we are going to run.
+	set cmd "info sources ${extra_args}"
+	set command_regex [string_to_regexp $cmd]
+
+	# Run the command and extract the results into INFO_SOURCES.
+	set objfile_name ""
+	set source_files {}
+	gdb_test_multiple $cmd "" {
+	    -re "${command_regex}\r\n" {
+		exp_continue
+	    }
+
+	    -re "^(\[^\r\n\]+):\r\n" {
+		set objfile_name $expect_out(1,string)
+		exp_continue
+	    }
+
+	    -re "^\\(Full debug information has not yet been read for this file\\.\\)\r\n" {
+		exp_continue
+	    }
+
+	    -re "^\r\n" {
+		exp_continue
+	    }
+
+	    -re "^$gdb_prompt $" {
+		pass $gdb_test_name
+	    }
+
+	    -re "^(\[^\r\n\]+)\r\n" {
+		if { $objfile_name == "" } {
+		    fail "${gdb_test_name} (no objfile name)"
+		    return
+		}
+
+		set files {}
+		foreach f [split $expect_out(1,string) ,] {
+		    lappend files [string trim $f]
+		}
+		set info_sources($objfile_name) $files
+		set $objfile_name ""
+		exp_continue
+	    }
+	}
+
+	# Now check ARGS agaisnt the values held in INFO_SOURCES map.
+	foreach {objfile sourcefile} $args {
+	    # First, figure out if we're expecting SOURCEFILE to be present,
+	    # or not.
+	    set present True
+	    set match_type "is"
+	    if {[string index $sourcefile 0] == "!"} {
+		set present False
+		set match_type "is not"
+		set sourcefile [string range $sourcefile 1 end]
+	    }
+
+	    # Figure out the path for SOURCEFILE that we're looking for.
+	    set sourcepath [file normalize ${srcdir}/${subdir}/${sourcefile}]
+
+	    # Make sure we handle the case where there are no source files
+	    # associated with a particular objfile.
+	    set source_list {}
+	    if [info exists info_sources($objfile)] {
+		set source_list $info_sources($objfile)
+	    }
+
+	    # Now perform the search, and check the results.
+	    set idx [lsearch -exact $source_list $sourcepath]
+	    gdb_assert {($present && $idx >= 0) || (!$present && $idx == -1)} \
+		"source file '$sourcefile' ${match_type} present for '[file tail $objfile]'"
+	}
+    }
+}
+
+# The actual tests.
+
+run_info_sources "" \
+    ${binfile} ${srcfile} \
+    ${binfile} ${testfile}-header.h \
+    ${solib_name} ${srcfile2} \
+    ${solib_name} ${testfile}-header.h
+
+run_info_sources "-basename info_sources_2" \
+    ${binfile} ${srcfile} \
+    ${binfile} ${testfile}-header.h \
+    ${solib_name} ${srcfile2} \
+    ${solib_name} ${testfile}-header.h
+
+run_info_sources "-basename \\.c" \
+    ${binfile} ${srcfile} \
+    ${binfile} !${testfile}-header.h \
+    ${solib_name} ${srcfile2} \
+    ${solib_name} !${testfile}-header.h
+
+run_info_sources "-basename -- -test\\.c" \
+    ${binfile} ${srcfile} \
+    ${binfile} !${testfile}-header.h \
+    ${solib_name} !${srcfile2} \
+    ${solib_name} !${testfile}-header.h
+
+run_info_sources "-basename -- -lib\\.c" \
+    ${binfile} !${srcfile} \
+    ${binfile} !${testfile}-header.h \
+    ${solib_name} ${srcfile2} \
+    ${solib_name} !${testfile}-header.h
-- 
2.25.4


^ permalink raw reply	[flat|nested] 38+ messages in thread

* PING! Re: [PATCHv3 0/5] "info sources" - group by objfile
  2021-06-07 18:32   ` [PATCHv3 " Andrew Burgess
                       ` (4 preceding siblings ...)
  2021-06-07 18:32     ` [PATCHv3 5/5] gdb: change info sources to group results by objfile Andrew Burgess
@ 2021-06-21 12:02     ` Andrew Burgess
  2021-06-25 20:08       ` Andrew Burgess
  5 siblings, 1 reply; 38+ messages in thread
From: Andrew Burgess @ 2021-06-21 12:02 UTC (permalink / raw)
  To: gdb-patches

I plan to push v3 later this week.

The first two versions of this patch have had no negative feedback,
and the changes in v3 are minor over v2.

Thanks,
Andrew


* Andrew Burgess <andrew.burgess@embecosm.com> [2021-06-07 19:32:22 +0100]:

> In V3:
> 
>  - 'info sources' now indicates when an objfile has no debug
>    information at all, this is a slight change of code, and an update
>    to the commit message in patch #5.
> 
>  - the MI output is updated to include the same information, there are
>    code changes, an update of the commit message, and changes to the
>    documentation in patch #4.
> 
>  - all the other patches are unchanged.
> 
> Thanks,
> Andrew
> 
> 
> ---
> 
> Andrew Burgess (5):
>   gdb: add new function quick_symbol_functions::has_unexpanded_symbols
>   gdb: make struct output_source_filename_data more C++ like
>   gdb/mi: add regexp filtering to -file-list-exec-source-files
>   gdb/mi: add new --group-by-objfile flag for
>     -file-list-exec-source-files
>   gdb: change info sources to group results by objfile
> 
>  gdb/ChangeLog                                 | 111 ++++++
>  gdb/NEWS                                      |  31 ++
>  gdb/doc/ChangeLog                             |  15 +
>  gdb/doc/gdb.texinfo                           | 176 +++++++--
>  gdb/dwarf2/read.c                             |  22 ++
>  gdb/mi/mi-cmd-file.c                          |  92 +++--
>  gdb/objfiles.h                                |   6 +
>  gdb/psympriv.h                                |   2 +
>  gdb/psymtab.c                                 |  18 +
>  gdb/quick-symbol.h                            |   6 +
>  gdb/symfile-debug.c                           |  25 ++
>  gdb/symtab.c                                  | 364 ++++++++++++------
>  gdb/symtab.h                                  |  59 +++
>  gdb/testsuite/ChangeLog                       |  19 +
>  .../gdb.base/info_sources_2-header.h          |  28 ++
>  gdb/testsuite/gdb.base/info_sources_2-lib.c   |  25 ++
>  gdb/testsuite/gdb.base/info_sources_2-test.c  |  26 ++
>  gdb/testsuite/gdb.base/info_sources_2.exp     | 169 ++++++++
>  gdb/testsuite/gdb.dwarf2/dw2-filename.exp     |   2 +-
>  gdb/testsuite/gdb.mi/mi-file.exp              |   2 +-
>  gdb/testsuite/gdb.mi/mi-info-sources-base.c   |  23 ++
>  gdb/testsuite/gdb.mi/mi-info-sources.c        |  25 ++
>  gdb/testsuite/gdb.mi/mi-info-sources.exp      | 184 +++++++++
>  23 files changed, 1239 insertions(+), 191 deletions(-)
>  create mode 100644 gdb/testsuite/gdb.base/info_sources_2-header.h
>  create mode 100644 gdb/testsuite/gdb.base/info_sources_2-lib.c
>  create mode 100644 gdb/testsuite/gdb.base/info_sources_2-test.c
>  create mode 100644 gdb/testsuite/gdb.base/info_sources_2.exp
>  create mode 100644 gdb/testsuite/gdb.mi/mi-info-sources-base.c
>  create mode 100644 gdb/testsuite/gdb.mi/mi-info-sources.c
>  create mode 100644 gdb/testsuite/gdb.mi/mi-info-sources.exp
> 
> -- 
> 2.25.4
> 

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: PING! Re: [PATCHv3 0/5] "info sources" - group by objfile
  2021-06-21 12:02     ` PING! Re: [PATCHv3 0/5] "info sources" - group " Andrew Burgess
@ 2021-06-25 20:08       ` Andrew Burgess
  0 siblings, 0 replies; 38+ messages in thread
From: Andrew Burgess @ 2021-06-25 20:08 UTC (permalink / raw)
  To: gdb-patches

* Andrew Burgess <andrew.burgess@embecosm.com> [2021-06-21 13:02:01 +0100]:

> I plan to push v3 later this week.

I've now pushed this series.

Thanks,
Andrew


> 
> The first two versions of this patch have had no negative feedback,
> and the changes in v3 are minor over v2.
> 
> Thanks,
> Andrew
> 
> 
> * Andrew Burgess <andrew.burgess@embecosm.com> [2021-06-07 19:32:22 +0100]:
> 
> > In V3:
> > 
> >  - 'info sources' now indicates when an objfile has no debug
> >    information at all, this is a slight change of code, and an update
> >    to the commit message in patch #5.
> > 
> >  - the MI output is updated to include the same information, there are
> >    code changes, an update of the commit message, and changes to the
> >    documentation in patch #4.
> > 
> >  - all the other patches are unchanged.
> > 
> > Thanks,
> > Andrew
> > 
> > 
> > ---
> > 
> > Andrew Burgess (5):
> >   gdb: add new function quick_symbol_functions::has_unexpanded_symbols
> >   gdb: make struct output_source_filename_data more C++ like
> >   gdb/mi: add regexp filtering to -file-list-exec-source-files
> >   gdb/mi: add new --group-by-objfile flag for
> >     -file-list-exec-source-files
> >   gdb: change info sources to group results by objfile
> > 
> >  gdb/ChangeLog                                 | 111 ++++++
> >  gdb/NEWS                                      |  31 ++
> >  gdb/doc/ChangeLog                             |  15 +
> >  gdb/doc/gdb.texinfo                           | 176 +++++++--
> >  gdb/dwarf2/read.c                             |  22 ++
> >  gdb/mi/mi-cmd-file.c                          |  92 +++--
> >  gdb/objfiles.h                                |   6 +
> >  gdb/psympriv.h                                |   2 +
> >  gdb/psymtab.c                                 |  18 +
> >  gdb/quick-symbol.h                            |   6 +
> >  gdb/symfile-debug.c                           |  25 ++
> >  gdb/symtab.c                                  | 364 ++++++++++++------
> >  gdb/symtab.h                                  |  59 +++
> >  gdb/testsuite/ChangeLog                       |  19 +
> >  .../gdb.base/info_sources_2-header.h          |  28 ++
> >  gdb/testsuite/gdb.base/info_sources_2-lib.c   |  25 ++
> >  gdb/testsuite/gdb.base/info_sources_2-test.c  |  26 ++
> >  gdb/testsuite/gdb.base/info_sources_2.exp     | 169 ++++++++
> >  gdb/testsuite/gdb.dwarf2/dw2-filename.exp     |   2 +-
> >  gdb/testsuite/gdb.mi/mi-file.exp              |   2 +-
> >  gdb/testsuite/gdb.mi/mi-info-sources-base.c   |  23 ++
> >  gdb/testsuite/gdb.mi/mi-info-sources.c        |  25 ++
> >  gdb/testsuite/gdb.mi/mi-info-sources.exp      | 184 +++++++++
> >  23 files changed, 1239 insertions(+), 191 deletions(-)
> >  create mode 100644 gdb/testsuite/gdb.base/info_sources_2-header.h
> >  create mode 100644 gdb/testsuite/gdb.base/info_sources_2-lib.c
> >  create mode 100644 gdb/testsuite/gdb.base/info_sources_2-test.c
> >  create mode 100644 gdb/testsuite/gdb.base/info_sources_2.exp
> >  create mode 100644 gdb/testsuite/gdb.mi/mi-info-sources-base.c
> >  create mode 100644 gdb/testsuite/gdb.mi/mi-info-sources.c
> >  create mode 100644 gdb/testsuite/gdb.mi/mi-info-sources.exp
> > 
> > -- 
> > 2.25.4
> > 

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCHv3 2/5] gdb: make struct output_source_filename_data more C++ like
  2021-06-07 18:32     ` [PATCHv3 2/5] gdb: make struct output_source_filename_data more C++ like Andrew Burgess
@ 2021-07-05 12:31       ` Tom de Vries
  2021-07-26 13:21         ` Andrew Burgess
  0 siblings, 1 reply; 38+ messages in thread
From: Tom de Vries @ 2021-07-05 12:31 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches

On 6/7/21 8:32 PM, Andrew Burgess wrote:
> +bool
> +info_sources_filter::matches (const char *fullname) const
> +{
> +  /* Does it match regexp?  */
> +  if (m_c_regexp.has_value ())
> +    {
> +      const char *to_match;
> +      std::string dirname;
> +
> +      switch (m_match_type)
> +        {
> +        case match_on::DIRNAME:
> +          dirname = ldirname (fullname);
> +          to_match = dirname.c_str ();
> +          break;
> +        case match_on::BASENAME:
> +          to_match = lbasename (fullname);
> +          break;
> +        case match_on::FULLNAME:
> +          to_match = fullname;
> +          break;
> +        }
> +
> +      if (m_c_regexp->exec (to_match, 0, NULL, 0) != 0)
> +        return false;
> +    }
> +
> +  return true;
> +}

When compiling with -O2, I run into:
...
src/gdb/symtab.c: In member function ‘bool
info_sources_filter::matches(const char*) const’:
src/gdb/symtab.c:4247:28: warning: ‘to_match’ may be used uninitialized
in this function [-Wmaybe-uninitialized]
 4247 |       if (m_c_regexp->exec (to_match, 0, NULL, 0) != 0)
      |           ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~
...

Thanks,
- Tom

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [PATCHv3 2/5] gdb: make struct output_source_filename_data more C++ like
  2021-07-05 12:31       ` Tom de Vries
@ 2021-07-26 13:21         ` Andrew Burgess
  0 siblings, 0 replies; 38+ messages in thread
From: Andrew Burgess @ 2021-07-26 13:21 UTC (permalink / raw)
  To: Tom de Vries; +Cc: gdb-patches

* Tom de Vries <tdevries@suse.de> [2021-07-05 14:31:22 +0200]:

> On 6/7/21 8:32 PM, Andrew Burgess wrote:
> > +bool
> > +info_sources_filter::matches (const char *fullname) const
> > +{
> > +  /* Does it match regexp?  */
> > +  if (m_c_regexp.has_value ())
> > +    {
> > +      const char *to_match;
> > +      std::string dirname;
> > +
> > +      switch (m_match_type)
> > +        {
> > +        case match_on::DIRNAME:
> > +          dirname = ldirname (fullname);
> > +          to_match = dirname.c_str ();
> > +          break;
> > +        case match_on::BASENAME:
> > +          to_match = lbasename (fullname);
> > +          break;
> > +        case match_on::FULLNAME:
> > +          to_match = fullname;
> > +          break;
> > +        }
> > +
> > +      if (m_c_regexp->exec (to_match, 0, NULL, 0) != 0)
> > +        return false;
> > +    }
> > +
> > +  return true;
> > +}
> 
> When compiling with -O2, I run into:
> ...
> src/gdb/symtab.c: In member function ‘bool
> info_sources_filter::matches(const char*) const’:
> src/gdb/symtab.c:4247:28: warning: ‘to_match’ may be used uninitialized
> in this function [-Wmaybe-uninitialized]
>  4247 |       if (m_c_regexp->exec (to_match, 0, NULL, 0) != 0)
>       |           ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~
> ...

Sorry I missed this.

Tom Tromey fixed this with this commit:

  commit b6aeb717a8bdaa9cc348ec88a5fdf059e1337580
  Author: Tom Tromey <tom@tromey.com>
  Date:   Mon Jul 5 11:44:54 2021 -0600

      Fix warning in symtab.c

Thanks,
Andrew

^ permalink raw reply	[flat|nested] 38+ messages in thread

end of thread, other threads:[~2021-07-26 13:21 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-26 17:06 [PATCH 0/4] New option for 'info sources', also better MI support Andrew Burgess
2021-04-26 17:07 ` [PATCH 1/4] gdb: add new function quick_symbol_functions::has_unexpanded_symbols Andrew Burgess
2021-05-13 14:38   ` Simon Marchi
2021-05-13 17:29     ` Tom Tromey
2021-05-13 14:46   ` Simon Marchi
2021-04-26 17:07 ` [PATCH 2/4] gdb: make struct output_source_filename_data more C++ like Andrew Burgess
2021-05-13 14:58   ` Simon Marchi
2021-04-26 17:07 ` [PATCH 3/4] gdb: add new -group-by-binary flag to info sources command Andrew Burgess
2021-04-26 17:34   ` Eli Zaretskii
2021-05-13 15:05   ` Simon Marchi
2021-05-15  8:45     ` Andrew Burgess
2021-05-15 13:19       ` Simon Marchi
2021-04-26 17:07 ` [PATCH 4/4] gdb/mi: extend -file-list-exec-source-files command Andrew Burgess
2021-04-26 17:39   ` Eli Zaretskii
2021-05-13 15:47   ` Simon Marchi
2021-05-13 10:34 ` [PATCH 0/4] New option for 'info sources', also better MI support Andrew Burgess
2021-05-19 11:12 ` [PATCHv2 0/5] "info sources" - group by objfile Andrew Burgess
2021-05-19 11:12   ` [PATCHv2 1/5] gdb: add new function quick_symbol_functions::has_unexpanded_symbols Andrew Burgess
2021-05-19 11:12   ` [PATCHv2 2/5] gdb: make struct output_source_filename_data more C++ like Andrew Burgess
2021-05-19 11:12   ` [PATCHv2 3/5] gdb/mi: add regexp filtering to -file-list-exec-source-files Andrew Burgess
2021-05-19 11:51     ` Eli Zaretskii
2021-05-19 11:12   ` [PATCHv2 4/5] gdb/mi: add new --group-by-objfile flag for -file-list-exec-source-files Andrew Burgess
2021-05-19 11:44     ` Eli Zaretskii
2021-05-19 11:12   ` [PATCHv2 5/5] gdb: change info sources to group results by objfile Andrew Burgess
2021-05-19 11:53     ` Eli Zaretskii
2021-06-03 13:08     ` Simon Marchi
2021-06-03  9:27   ` [PATCHv2 0/5] "info sources" - group " Andrew Burgess
2021-06-03 13:15     ` Simon Marchi
2021-06-07 18:32   ` [PATCHv3 " Andrew Burgess
2021-06-07 18:32     ` [PATCHv3 1/5] gdb: add new function quick_symbol_functions::has_unexpanded_symbols Andrew Burgess
2021-06-07 18:32     ` [PATCHv3 2/5] gdb: make struct output_source_filename_data more C++ like Andrew Burgess
2021-07-05 12:31       ` Tom de Vries
2021-07-26 13:21         ` Andrew Burgess
2021-06-07 18:32     ` [PATCHv3 3/5] gdb/mi: add regexp filtering to -file-list-exec-source-files Andrew Burgess
2021-06-07 18:32     ` [PATCHv3 4/5] gdb/mi: add new --group-by-objfile flag for -file-list-exec-source-files Andrew Burgess
2021-06-07 18:32     ` [PATCHv3 5/5] gdb: change info sources to group results by objfile Andrew Burgess
2021-06-21 12:02     ` PING! Re: [PATCHv3 0/5] "info sources" - group " Andrew Burgess
2021-06-25 20:08       ` Andrew Burgess

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).