From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wr1-x42d.google.com (mail-wr1-x42d.google.com [IPv6:2a00:1450:4864:20::42d]) by sourceware.org (Postfix) with ESMTPS id 5A70B3894438 for ; Mon, 7 Jun 2021 18:32:40 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 5A70B3894438 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embecosm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=embecosm.com Received: by mail-wr1-x42d.google.com with SMTP id f2so18680995wri.11 for ; Mon, 07 Jun 2021 11:32:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=DicvQ+DK1GOLDKvsjyxLUsWcaXAWMBgJq2uxaUt/iIY=; b=LH8jGET195lXzU2x8zXPYAPWXpNrMflgyCzvdAnGspMlPe16NLzGhIriGYE65+MlrY UcMXa35NlBVTIGep+9fHSZKkEsOa11Z4BP65MxGaAsY1fg/awFJBcK1H038/R9rEYsLe 2GPIAyRksrL158WyiTmYvbZZI0E1I0iA+tscOSRwuBzJ4fYhbaf9mWYBYWQvvJJDLKS9 1Go3LcL5UwawFY50TidRpXGBwJyDvMt4YozWb9LmyQQGUGm3zqZzOP6dYWkmZoJxtypa XUN1hkeE3fel4T8vIEaZkG3Mq89kwybVbyoHk6EJp+dQwSScklo8ixFgnZGAfeYZKoXg jIqg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=DicvQ+DK1GOLDKvsjyxLUsWcaXAWMBgJq2uxaUt/iIY=; b=Zn0+e+7Z7/v0045jglYfyyCj7w+wUIejuIsmfQxNe8Xtsl+1R/2/m2L21sEUWNjhrB qeNWd+Zz4z8YrYXFlzHdtQa/ftgEAO5SEWGCpDz+32DnO22PFHT4xpDGUUjxP3mZjQUf GRmyrMOvd9YfCC4KcW46YGveyBlKZMB39lrz5l1E0tpSdQkkGLPI0cAA3B95+jKhgibw UggJ/Fmcf7DFpTLSKgk6lxe8O+U353hkD16gxnz07y6Fi5WicYPEl9W+7qMZGJkgIggf 4gQvqUqGlVvLoY48gHW3ijl6lTCUeQG25so1ONpVT/wIS2/G0z0PPAVTADXj/lD9WdOj kSRw== X-Gm-Message-State: AOAM533AvUpC08qAThz1lJuqcy+ZWUYYupWIwYrTUhWQNECSCN0MilNh U+ok90gS7dbxi1REA1QEhlX0ZLiVIdTFOw== X-Google-Smtp-Source: ABdhPJxqJWmHWGVCtip+JfWZwGrZetNranLTRAK6ENoNJVsR1quvqK5qDFc0Fgdrkae9PI1e8aXSiw== X-Received: by 2002:adf:e8c1:: with SMTP id k1mr19115843wrn.413.1623090758351; Mon, 07 Jun 2021 11:32:38 -0700 (PDT) Received: from localhost (host109-151-46-70.range109-151.btcentralplus.com. [109.151.46.70]) by smtp.gmail.com with ESMTPSA id j7sm14848389wrm.93.2021.06.07.11.32.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Jun 2021 11:32:37 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Subject: [PATCHv3 3/5] gdb/mi: add regexp filtering to -file-list-exec-source-files Date: Mon, 7 Jun 2021 19:32:25 +0100 Message-Id: <504075e85591ea6376bdc915eaa86538235862fa.1623090529.git.andrew.burgess@embecosm.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-12.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 07 Jun 2021 18:32:44 -0000 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) : Take uiout argument, store into m_uiout. : Rewrite comment, add additional arguments to declaration. : Send more arguments to output. : 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) } -/* 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 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 output_tuple; + gdb::optional 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 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 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 . */ + +/* 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 . */ + +/* 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 . + +# 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