From bd742128ba3b0eebda581a26c5bfa52ac0995584 Mon Sep 17 00:00:00 2001 From: Andrew Burgess Date: Tue, 18 May 2021 14:27:25 +0100 Subject: [PATCH] gdb: change info sources to group results by objfile 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) : Delete declaration. : 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) : 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/ChangeLog b/gdb/ChangeLog index 637fd096a93..41f98e81287 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,17 @@ +2021-06-25 Andrew Burgess + + * NEWS: Mention changes to 'info sources'. + * symtab.c (info_sources_filter::print): Delete. + (struct output_source_filename_data) : Delete + declaration. : 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) : Delete. + 2021-06-25 Andrew Burgess * NEWS: Mention additions to -file-list-exec-source-files. diff --git a/gdb/NEWS b/gdb/NEWS index f37ad425d3a..7f3ed4f02f0 100644 --- 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* diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 20ea7f7d12d..c9f30e565e1 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,8 @@ +2021-06-25 Andrew Burgess + + * gdb.texinfo (Symbols): Document new output format for 'info + sources'. + 2021-06-25 Andrew Burgess * gdb.texinfo (GDB/MI File Commands): Document --group-by-objfile diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 19b6a5f2120..f1c3e7ba847 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -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] 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 output_tuple; gdb::optional 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 968b4476993..471ae9ef448 100644 --- a/gdb/symtab.h +++ b/gdb/symtab.h @@ -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. */ diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 8a8c7f22ea3..26dcea62511 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2021-06-25 Andrew Burgess + + * 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 * 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 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 . */ + +#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 . */ + + +#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 . */ + + +#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 . + +# 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.30.2