gdb: change info sources to group results by objfile
authorAndrew Burgess <andrew.burgess@embecosm.com>
Tue, 18 May 2021 13:27:25 +0000 (14:27 +0100)
committerAndrew Burgess <andrew.burgess@embecosm.com>
Fri, 25 Jun 2021 19:54:29 +0000 (20:54 +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:
  (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
gdb/NEWS
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/symtab.c
gdb/symtab.h
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/info_sources_2-header.h [new file with mode: 0644]
gdb/testsuite/gdb.base/info_sources_2-lib.c [new file with mode: 0644]
gdb/testsuite/gdb.base/info_sources_2-test.c [new file with mode: 0644]
gdb/testsuite/gdb.base/info_sources_2.exp [new file with mode: 0644]

index 637fd096a9306c02f383b49c3a450fd8ba964349..41f98e81287fae70ef7ebef6cd9c0dd99b709076 100644 (file)
@@ -1,3 +1,17 @@
+2021-06-25  Andrew Burgess  <andrew.burgess@embecosm.com>
+
+       * 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.
+
 2021-06-25  Andrew Burgess  <andrew.burgess@embecosm.com>
 
        * NEWS: Mention additions to -file-list-exec-source-files.
index f37ad425d3ae7ca6a4f59b51a32b27d00aa40210..7f3ed4f02f08fe7c5b68fc9ae256dbfe48626034 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -221,6 +221,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*
index 20ea7f7d12d9e4a560d96bdfb5b833a27e05fbd7..c9f30e565e1ee8d3bf18e4c65e7fd80597074796 100644 (file)
@@ -1,3 +1,8 @@
+2021-06-25  Andrew Burgess  <andrew.burgess@embecosm.com>
+
+       * gdb.texinfo (Symbols): Document new output format for 'info
+       sources'.
+
 2021-06-25  Andrew Burgess  <andrew.burgess@embecosm.com>
 
        * gdb.texinfo (GDB/MI File Commands): Document --group-by-objfile
index 19b6a5f2120258da4731d001438f22a6a9afdbb2..f1c3e7ba847df4afa526a75921dada2840b477d3 100644 (file)
@@ -19334,20 +19334,36 @@ preprocessor macros.
 
 
 @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]
index cd6da0631417b28b28f7cd0ff2a7fd20c85e0d78..7fd037f970139c7516b7095fb95328fecf2a97d2 100644 (file)
@@ -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
index 968b4476993adb7f743fc6a82c1576214452e87b..471ae9ef4480a8359a23f2ca0960ff4b70e2282d 100644 (file)
@@ -2420,11 +2420,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.  */
index 8a8c7f22ea38bca6022a3711a24e12d067a2771c..26dcea625118407f5ed3d6097467894e068d809a 100644 (file)
@@ -1,3 +1,10 @@
+2021-06-25  Andrew Burgess  <andrew.burgess@embecosm.com>
+
+       * 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.
+
 2021-06-25  Andrew Burgess  <andrew.burgess@embecosm.com>
 
        * gdb.mi/mi-info-sources.exp: Add additional tests.
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 (file)
index 0000000..b3379ba
--- /dev/null
@@ -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 (file)
index 0000000..7df1a81
--- /dev/null
@@ -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 (file)
index 0000000..87a030a
--- /dev/null
@@ -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 (file)
index 0000000..3aed25b
--- /dev/null
@@ -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
This page took 0.058311 seconds and 4 git commands to generate.