From patchwork Tue Aug 20 17:10:31 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 96174 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 99F473870852 for ; Tue, 20 Aug 2024 17:11:31 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id 9A09E38449C8 for ; Tue, 20 Aug 2024 17:10:51 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 9A09E38449C8 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 9A09E38449C8 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724173854; cv=none; b=LPQm26893o5Babz5b3vEbCxlz/OoH0a9q6VN6UVSA3HmNv4wM8wLf/ZYSrz6px7Xuwfe+No1hZ8dHkO69nPfX6TV8UkcIsCiQ1b8nfLmcjNN2wPJtwK+HTvwCweWy+aYJgVPuwOmmYvcqiCzsZMezL3yMipqmus74L2K5yLAM74= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724173854; c=relaxed/simple; bh=WsIcto8Pw324T4As0v9L7iEr2pbRU2xvMhfslkuosM0=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=DurHRH+ULwsm12waheYjgG0IPhmKtbBjMgdjeHqwcVBk7dvRNnY0jGNGztqFuS6NFgg4s5t96qA0bRkUuW9K4k8DnF2sbz5NiUkykKQWswtOHt+vHfWb5r9u4REyMgWXfHju0QcR6gDNUyJ+MBuJ7CaZQ8nlL4wq11yOZpiaIng= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1724173851; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=lq4kkaOolZR8dybAnTrQRt4t1JTHKg2/oMlyN1e0HuE=; b=Vs5Rpo6scJBpDxUG5RTLDNbH1FhbYrD1wWcvKfQaZyI+cTUb9K9jn7QY8Pmko185WL9VMC lmrHtbbPObmPJemxezUoE3mSOgauJggfq0/0UfPAsnS8DAb1n2Iw9fySEUa/+bgCvD5Yf5 +iapKFN5eFlB/yT80sP8wh0qyoBSdMA= Received: from mail-wr1-f72.google.com (mail-wr1-f72.google.com [209.85.221.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-610-CpCccBQJPyeMJAWZLg_DQg-1; Tue, 20 Aug 2024 13:10:50 -0400 X-MC-Unique: CpCccBQJPyeMJAWZLg_DQg-1 Received: by mail-wr1-f72.google.com with SMTP id ffacd0b85a97d-3717cc80ce1so3550819f8f.0 for ; Tue, 20 Aug 2024 10:10:49 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1724173848; x=1724778648; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=lq4kkaOolZR8dybAnTrQRt4t1JTHKg2/oMlyN1e0HuE=; b=lC6VULubZVDPcwEswFy1bSXhE+dNsn9OBY5kl9NerEwopkWqtJjSDVUELPgXHKUh4e x83og419PmfDCZkrW9EsqdUu3CyuAyf0BXGpfHDDXZfvVWQaLkdc5MSz/P5ocUJPdtZj PJZY/Rlnxh5KQcF0332anPqQy+wNKcCMVsHrFvCU5ZUXunQ4YfCGzn/0nCkCjF6VKf0D PNqUe6iJU+kwlVxpG4LTJgFSk9bTXtTamu2Oe3HD/FsLhLltzIjmi7r0k6I8Sea/FX6u HApzUQoGgULgbCeU+8ctNJZc550v0+Yo9Id2YCVXdX9yyPO8gmLnVHBLVRmQ6HdaRq3z u73A== X-Gm-Message-State: AOJu0Yxu1U9yVqna96RlAazbwr8msASRic3rtphIIlfu/Ejl5IEEJ9D3 dCa+IFMEiU1n70iXK5bhTLQiC95fxx3e+fWGCzOEZ2FxrBcgRWsWshpZTTpqUYyR9FST6aALC/A LtmIJ3Zbl0RECSGTcfLmNVg4isZ8QIiIQvLEqiQr/pkjMZ8LA94vrMfarBOpMtPW1kiHptkYQp+ Mg3mz28GuQdGxL05pFfqLtpjwZigRudevXN4y7oxoXraw= X-Received: by 2002:a5d:404c:0:b0:371:8341:d589 with SMTP id ffacd0b85a97d-37194316ac0mr12984959f8f.12.1724173848033; Tue, 20 Aug 2024 10:10:48 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHi3Mtvb6lZyIeipSb2F2i12W/fE19fp/D4AULcEqc/py1UYt8MlEiva9YDIXIv5U2vfki+gw== X-Received: by 2002:a5d:404c:0:b0:371:8341:d589 with SMTP id ffacd0b85a97d-37194316ac0mr12984910f8f.12.1724173846742; Tue, 20 Aug 2024 10:10:46 -0700 (PDT) Received: from localhost (178.126.90.146.dyn.plus.net. [146.90.126.178]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-371898ac074sm13529575f8f.106.2024.08.20.10.10.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 20 Aug 2024 10:10:46 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv5 01/14] gdb: split apart two different types of filename completion Date: Tue, 20 Aug 2024 18:10:31 +0100 Message-Id: <952b55483af16f9633d78b30626469ef0a1a2030.1724173728.git.aburgess@redhat.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-10.3 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org Unfortunately we have two different types of filename completion in GDB. The majority of commands have what I call unquoted filename completion, this is for commands like 'set logging file ...', 'target core ...', and 'add-auto-load-safe-path ...'. For these commands everything after the command name (that is not a command option) is treated as a single filename. If the filename contains white space then this does not need to be escaped, nor does the filename need to be quoted. In fact, the filename argument is not de-quoted, and does not have any escaping removed, so if a user does try to add such things, they will be treated as part of the filename. As an example: (gdb) target core "/path/that contains/some white space" Will look for a directory calls '"' (double quotes) in the local directory. A small number of commands do de-quote and remove escapes from filename arguments. These command accept what I call quoted and escaped filenames. Right now these are the commands that specify the file for GDB to debug, so: file exec-file symbol-file add-symbol-file remove-symbol-file As an example of this in action: (gdb) file "/path/that contains/some white space" In this case GDB would load the file: /path/that contains/some white space Current filename completion always assumes that filenames can be quoted, though escaping doesn't work in completion right now. But the assumption that quoting is allowed is clearly wrong. This commit splits filename completion into two. The existing filename_completer is retained, and is used for unquoted filenames. A second filename_maybe_quoted_completer is added which can be used for completing quoted filenames. The filename completion test has been extended to cover more cases. As part of the extended testing I need to know the character that should be used to separate filenames within a path. For this TCL 8.6+ has $::tcl_platform(pathSeparator). To support older versions of TCL I've added some code to testsuite/lib/gdb.exp. You might notice that after this commit the completion for unquoted files is all done in the brkchars phase, that is the function filename_completer_handle_brkchars calculates the completions and marks the completion_tracker as using a custom word point. The reason for this is that we don't want to break on white space for this completion, but if we rely on readline to find the completion word, readline will consider the entire command line, and with no white space in the word break character set, readline will end up using the entire command line as the word to complete. For now at least, the completer for quoted filenames does generate its completions during the completion phase, though this is going to change in a later commit. --- gdb/completer.c | 86 +++++-- gdb/completer.h | 24 +- gdb/exec.c | 4 +- gdb/guile/scm-cmd.c | 2 +- gdb/python/py-cmd.c | 2 +- gdb/symfile.c | 4 +- .../gdb.base/filename-completion.exp | 209 ++++++++++++++---- gdb/testsuite/lib/gdb.exp | 10 + 8 files changed, 269 insertions(+), 72 deletions(-) diff --git a/gdb/completer.c b/gdb/completer.c index 1008ec23ba5..93eb8db6db0 100644 --- a/gdb/completer.c +++ b/gdb/completer.c @@ -182,6 +182,17 @@ static const char gdb_completer_file_name_break_characters[] = " \t\n*|\"';:?><"; #endif +/* When completing on file names, for commands that don't accept quoted + file names, the only character that can be used as a word separator is + the path separator. Every other character is treated as a literal + character within the filename. */ +static const char gdb_completer_path_break_characters[] = +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + ";"; +#else + ":"; +#endif + /* Characters that can be used to quote expressions. Note that we can't include '"' (double quote) because the gdb C parser treats such quoted sequences as strings. */ @@ -203,15 +214,15 @@ noop_completer (struct cmd_list_element *ignore, { } -/* Complete on filenames. */ +/* Generate filename completions of WORD, storing the completions into + TRACKER. This is used for generating completions for commands that + only accept unquoted filenames as well as for commands that accept + quoted and escaped filenames. */ -void -filename_completer (struct cmd_list_element *ignore, - completion_tracker &tracker, - const char *text, const char *word) +static void +filename_completer_generate_completions (completion_tracker &tracker, + const char *word) { - rl_completer_quote_characters = gdb_completer_file_name_quote_characters; - int subsequent_name = 0; while (1) { @@ -249,13 +260,13 @@ filename_completer (struct cmd_list_element *ignore, } } -/* The corresponding completer_handle_brkchars - implementation. */ +/* The brkchars callback used when completing filenames that can be + quoted. */ static void -filename_completer_handle_brkchars (struct cmd_list_element *ignore, - completion_tracker &tracker, - const char *text, const char *word) +filename_maybe_quoted_completer_handle_brkchars + (struct cmd_list_element *ignore, completion_tracker &tracker, + const char *text, const char *word) { set_rl_completer_word_break_characters (gdb_completer_file_name_break_characters); @@ -263,6 +274,50 @@ filename_completer_handle_brkchars (struct cmd_list_element *ignore, rl_completer_quote_characters = gdb_completer_file_name_quote_characters; } +/* Complete on filenames. This is for commands that accepts possibly + quoted filenames. */ + +void +filename_maybe_quoted_completer (struct cmd_list_element *ignore, + completion_tracker &tracker, + const char *text, const char *word) +{ + filename_maybe_quoted_completer_handle_brkchars (ignore, tracker, + text, word); + filename_completer_generate_completions (tracker, word); +} + +/* The brkchars callback used by commands that don't accept quoted + filenames. */ + +static void +filename_completer_handle_brkchars + (struct cmd_list_element *ignore, completion_tracker &tracker, + const char *text, const char *word) +{ + gdb_assert (word == nullptr); + + set_rl_completer_word_break_characters (gdb_completer_path_break_characters); + rl_completer_quote_characters = nullptr; + rl_filename_quoting_desired = 0; + + tracker.set_use_custom_word_point (true); + word = advance_to_filename_complete_word_point (tracker, text); + filename_completer (ignore, tracker, text, word); +} + +/* See completer.h. */ + +void +filename_completer + (struct cmd_list_element *ignore, completion_tracker &tracker, + const char *text, const char *word) +{ + gdb_assert (tracker.use_custom_word_point ()); + gdb_assert (word != nullptr); + filename_completer_generate_completions (tracker, word); +} + /* Find the bounds of the current word for completion purposes, and return a pointer to the end of the word. This mimics (and is a modified version of) readline's _rl_find_completion_word internal @@ -447,8 +502,8 @@ const char * advance_to_filename_complete_word_point (completion_tracker &tracker, const char *text) { - const char *brk_chars = gdb_completer_file_name_break_characters; - const char *quote_chars = gdb_completer_file_name_quote_characters; + const char *brk_chars = gdb_completer_path_break_characters; + const char *quote_chars = nullptr; return advance_to_completion_word (tracker, brk_chars, quote_chars, text); } @@ -1880,6 +1935,9 @@ completer_handle_brkchars_func_for_completer (completer_ftype *fn) if (fn == filename_completer) return filename_completer_handle_brkchars; + if (fn == filename_maybe_quoted_completer) + return filename_maybe_quoted_completer_handle_brkchars; + if (fn == location_completer) return location_completer_handle_brkchars; diff --git a/gdb/completer.h b/gdb/completer.h index 98a12f3907c..c6d064ec9d6 100644 --- a/gdb/completer.h +++ b/gdb/completer.h @@ -563,9 +563,10 @@ extern completion_result const char *advance_to_expression_complete_word_point (completion_tracker &tracker, const char *text); -/* Assuming TEXT is an filename, find the completion word point for - TEXT, emulating the algorithm readline uses to find the word - point. */ +/* Assuming TEXT is a filename, find the completion word point for TEXT, + emulating the algorithm readline uses to find the word point. The + filenames that are located by this function assume no filename + quoting, this function should be paired with filename_completer. */ extern const char *advance_to_filename_complete_word_point (completion_tracker &tracker, const char *text); @@ -573,10 +574,27 @@ extern void noop_completer (struct cmd_list_element *, completion_tracker &tracker, const char *, const char *); +/* Filename completer for commands that don't accept quoted filenames. + This completer does support completing a list of filenames that are + separated with the path separator (':' for UNIX and ';' for MS-DOS). + + When adding a new command it is better to write the command so it + accepts quoted filenames and use filename_maybe_quoted_completer, for + examples see the 'exec' and 'exec-file' commands. */ + extern void filename_completer (struct cmd_list_element *, completion_tracker &tracker, const char *, const char *); +/* Filename completer for commands where the filename argument can be + quoted. This completer also supports completing a list of filenames + that are separated with the path separator (':' for UNIX and ';' for + MS-DOS). */ + +extern void filename_maybe_quoted_completer (struct cmd_list_element *, + completion_tracker &tracker, + const char *, const char *); + extern void expression_completer (struct cmd_list_element *, completion_tracker &tracker, const char *, const char *); diff --git a/gdb/exec.c b/gdb/exec.c index 63eee4297bc..f30ed62e4b3 100644 --- a/gdb/exec.c +++ b/gdb/exec.c @@ -1074,14 +1074,14 @@ and it is the program executed when you use the `run' command.\n\ If FILE cannot be found as specified, your execution directory path\n\ ($PATH) is searched for a command of that name.\n\ No arg means to have no executable file and no symbols."), &cmdlist); - set_cmd_completer (c, filename_completer); + set_cmd_completer (c, filename_maybe_quoted_completer); c = add_cmd ("exec-file", class_files, exec_file_command, _("\ Use FILE as program for getting contents of pure memory.\n\ If FILE cannot be found as specified, your execution directory path\n\ is searched for a command of that name.\n\ No arg means have no executable file."), &cmdlist); - set_cmd_completer (c, filename_completer); + set_cmd_completer (c, filename_maybe_quoted_completer); add_com ("section", class_files, set_section_command, _("\ Change the base address of section SECTION of the exec file to ADDR.\n\ diff --git a/gdb/guile/scm-cmd.c b/gdb/guile/scm-cmd.c index 2a5507686b0..8255529a2fe 100644 --- a/gdb/guile/scm-cmd.c +++ b/gdb/guile/scm-cmd.c @@ -110,7 +110,7 @@ struct cmdscm_completer static const struct cmdscm_completer cmdscm_completers[] = { { "COMPLETE_NONE", noop_completer }, - { "COMPLETE_FILENAME", filename_completer }, + { "COMPLETE_FILENAME", filename_maybe_quoted_completer }, { "COMPLETE_LOCATION", location_completer }, { "COMPLETE_COMMAND", command_completer }, { "COMPLETE_SYMBOL", symbol_completer }, diff --git a/gdb/python/py-cmd.c b/gdb/python/py-cmd.c index f83b45dd210..4deeb35eba0 100644 --- a/gdb/python/py-cmd.c +++ b/gdb/python/py-cmd.c @@ -39,7 +39,7 @@ struct cmdpy_completer static const struct cmdpy_completer completers[] = { { "COMPLETE_NONE", noop_completer }, - { "COMPLETE_FILENAME", filename_completer }, + { "COMPLETE_FILENAME", filename_maybe_quoted_completer }, { "COMPLETE_LOCATION", location_completer }, { "COMPLETE_COMMAND", command_completer }, { "COMPLETE_SYMBOL", symbol_completer }, diff --git a/gdb/symfile.c b/gdb/symfile.c index cf7ab0b94e6..c3cd961c0b9 100644 --- a/gdb/symfile.c +++ b/gdb/symfile.c @@ -3814,7 +3814,7 @@ Usage: symbol-file [-readnow | -readnever] [-o OFF] FILE\n\ OFF is an optional offset which is added to each section address.\n\ The `file' command can also load symbol tables, as well as setting the file\n\ to execute.\n" READNOW_READNEVER_HELP), &cmdlist); - set_cmd_completer (c, filename_completer); + set_cmd_completer (c, filename_maybe_quoted_completer); c = add_cmd ("add-symbol-file", class_files, add_symbol_file_command, _("\ Load symbols from FILE, assuming FILE has been dynamically loaded.\n\ @@ -3828,7 +3828,7 @@ OFF is an optional offset which is added to the default load addresses\n\ of all sections for which no other address was specified.\n" READNOW_READNEVER_HELP), &cmdlist); - set_cmd_completer (c, filename_completer); + set_cmd_completer (c, filename_maybe_quoted_completer); c = add_cmd ("remove-symbol-file", class_files, remove_symbol_file_command, _("\ diff --git a/gdb/testsuite/gdb.base/filename-completion.exp b/gdb/testsuite/gdb.base/filename-completion.exp index b700977cec5..37629bfbf77 100644 --- a/gdb/testsuite/gdb.base/filename-completion.exp +++ b/gdb/testsuite/gdb.base/filename-completion.exp @@ -23,8 +23,16 @@ load_lib completion-support.exp # # root/ [ DIRECTORY ] # aaa/ [ DIRECTORY ] +# aa bb [ FILE ] +# aa cc [ FILE ] +# aaa/ [ DIRECTORY ] # bb1/ [ DIRECTORY ] # bb2/ [ DIRECTORY ] +# dir 1/ [ DIRECTORY ] +# unique file [ FILE ] +# dir 2/ [ DIRECTORY ] +# file 1 [ FILE ] +# file 2 [ FILE ] # cc1/ [ DIRECTORY ] # cc2 [ FILE ] proc setup_directory_tree {} { @@ -36,68 +44,170 @@ proc setup_directory_tree {} { remote_exec host "mkdir -p ${root}/bb2" remote_exec host "mkdir -p ${root}/cc1" remote_exec host "touch ${root}/cc2" - remote_exec host "touch \"${root}/aaa/aa bb\"" remote_exec host "touch \"${root}/aaa/aa cc\"" + remote_exec host "mkdir -p \"${root}/bb2/dir 1\"" + remote_exec host "mkdir -p \"${root}/bb2/dir 2\"" + remote_exec host "touch \"${root}/bb2/dir 1/unique file\"" + remote_exec host "touch \"${root}/bb2/dir 2/file 1\"" + remote_exec host "touch \"${root}/bb2/dir 2/file 2\"" return $root } -# Run filename completetion tests. ROOT is the base directory as -# returned from setup_directory_tree, though, if ROOT is a -# sub-directory of the user's home directory ROOT might have been -# modified to replace the $HOME prefix with a single "~" character. -proc run_tests { root } { - - # Completing 'thread apply all ...' commands uses a custom word - # point. At one point we had a bug where doing this would break - # completion of quoted filenames that contained white space. - test_gdb_complete_unique "thread apply all hel" \ - "thread apply all help" " " false \ - "complete a 'thread apply all' command" - - foreach_with_prefix qc [list "" "'" "\""] { - test_gdb_complete_none "file ${qc}${root}/xx" \ - "expand a non-existent filename" - - test_gdb_complete_unique "file ${qc}${root}/a" \ - "file ${qc}${root}/aaa/" "" false \ - "expand a unique filename" - - test_gdb_complete_multiple "file ${qc}${root}/" \ - "b" "b" { - "bb1/" - "bb2/" - } "" "${qc}" false \ - "expand multiple directory names" - - test_gdb_complete_multiple "file ${qc}${root}/" \ - "c" "c" { - "cc1/" - "cc2" - } "" "${qc}" false \ - "expand mixed directory and file names" - - # GDB does not currently escape word break characters - # (e.g. white space) correctly in unquoted filenames. - if { $qc ne "" } { - set sp " " - - test_gdb_complete_multiple "file ${qc}${root}/aaa/" \ - "a" "a${sp}" { - "aa bb" - "aa cc" +# Run filename completetion tests for those command that accept quoting and +# escaping of the filename argument. +# +# ROOT is the base directory as returned from setup_directory_tree, though, +# if ROOT is a sub-directory of the user's home directory ROOT might have +# been modified to replace the $HOME prefix with a single "~" character. +proc run_quoting_and_escaping_tests { root } { + # Test all the commands which allow quoting of filenames, and + # which require whitespace to be escaped in unquoted filenames. + foreach_with_prefix cmd { file exec-file symbol-file add-symbol-file } { + gdb_start + + # Completing 'thread apply all ...' commands uses a custom word + # point. At one point we had a bug where doing this would break + # completion of quoted filenames that contained white space. + test_gdb_complete_unique "thread apply all hel" \ + "thread apply all help" " " false \ + "complete a 'thread apply all' command" + + foreach_with_prefix qc [list "" "'" "\""] { + test_gdb_complete_none "$cmd ${qc}${root}/xx" \ + "expand a non-existent filename" + + test_gdb_complete_unique "$cmd ${qc}${root}/a" \ + "$cmd ${qc}${root}/aaa/" "" false \ + "expand a unique filename" + + test_gdb_complete_multiple "$cmd ${qc}${root}/" \ + "b" "b" { + "bb1/" + "bb2/" + } "" "${qc}" false \ + "expand multiple directory names" + + test_gdb_complete_multiple "$cmd ${qc}${root}/" \ + "c" "c" { + "cc1/" + "cc2" } "" "${qc}" false \ - "expand filenames containing spaces" + "expand mixed directory and file names" + + # GDB does not currently escape word break characters + # (e.g. white space) correctly in unquoted filenames. + if { $qc ne "" } { + set sp " " + + test_gdb_complete_multiple "$cmd ${qc}${root}/aaa/" \ + "a" "a${sp}" { + "aa bb" + "aa cc" + } "" "${qc}" false \ + "expand filenames containing spaces" + } } + + gdb_exit } } -gdb_start +# Helper for run_unquoted_tests. ROOT is the root directory as setup +# by setup_directory_tree. CMD is the GDB command to test. PREFIX is +# a possible prefix filename to prepend to the filename being +# completed. +proc run_unquoted_tests_core { root cmd { prefix "" } } { + gdb_start + + if { $prefix != "" } { + # Platform specific path separator (':' on UNIX, ';' on MS-DOS). + set pathsep $::tcl_platform(pathSeparator) + + set prefix ${prefix}${pathsep} + } + + test_gdb_complete_none "$cmd ${prefix}${root}${root}/xx" \ + "expand a non-existent filename" + + test_gdb_complete_unique "$cmd ${prefix}${root}/a" \ + "$cmd ${prefix}${root}/aaa/" "" false \ + "expand a unique filename" + + test_gdb_complete_unique "$cmd ${prefix}${root}/bb2/dir 1/uni" \ + "$cmd ${prefix}${root}/bb2/dir 1/unique file" " " false \ + "expand a unique filename containing whitespace" + + test_gdb_complete_multiple "$cmd ${prefix}${root}/" \ + "b" "b" { + "bb1/" + "bb2/" + } "" "" false \ + "expand multiple directory names" + + test_gdb_complete_multiple "$cmd ${prefix}${root}/" \ + "c" "c" { + "cc1/" + "cc2" + } "" "" false \ + "expand mixed directory and file names" + + test_gdb_complete_multiple "$cmd ${prefix}${root}/aaa/" \ + "a" "a " { + "aa bb" + "aa cc" + } "" "" false \ + "expand filenames containing spaces" + + test_gdb_complete_multiple "$cmd ${prefix}${root}/bb2/dir 2/" \ + "fi" "le " { + "file 1" + "file 2" + } "" "" false \ + "expand filenames containing spaces in path" + + gdb_exit +} + + +# Run filename completetion tests for a sample of commands that take an +# unquoted, unescaped filename as an argument. Only a sample of commands +# are (currently) tested as there's a lot of commands that accept this style +# of filename argument. +# +# ROOT is the base directory as returned from setup_directory_tree, though, +# if ROOT is a sub-directory of the user's home directory ROOT might have +# been modified to replace the $HOME prefix with a single "~" character. +proc run_unquoted_tests { root } { + # Test all the commands which allow quoting of filenames, and + # which require whitespace to be escaped in unquoted filenames. + foreach_with_prefix cmd { "maint print c-tdesc" "set logging file" \ + "target core" "add-auto-load-safe-path" } { + run_unquoted_tests_core $root $cmd + } + + foreach prefix [list \ + "${root}/bb2/dir 1" \ + "${root}/bb2/dir 1/unique file" \ + "${root}/cc1" \ + "${root}/cc2"] { + + # Don't use the full path in the test name, just use the + # part after the ROOT directory. + set id [string range $prefix [string length ${root}] end] + with_test_prefix "prefix=$id" { + foreach_with_prefix cmd { "add-auto-load-safe-path" "path" } { + run_unquoted_tests_core $root $cmd $prefix + } + } + } +} set root [setup_directory_tree] -run_tests $root +run_quoting_and_escaping_tests $root +run_unquoted_tests $root # This test relies on using the $HOME directory. We could make this # work for remote hosts, but right now, this isn't supported. @@ -114,7 +224,8 @@ if {![is_remote host]} { with_test_prefix "with tilde" { # And rerun the tests. - run_tests $tilde_root + run_quoting_and_escaping_tests $tilde_root + run_unquoted_tests $tilde_root } } } diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index 1c49b6a36d7..c0b91c2e850 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -1697,6 +1697,16 @@ if { [tcl_version_at_least 8 6] == 0 } { return $res } + + # ::tcl_platform(pathSeparator) was added in 8.6. + switch $::tcl_platform(platform) { + windows { + set ::tcl_platform(pathSeparator) ; + } + default { + set ::tcl_platform(pathSeparator) : + } + } } if { [tcl_version_at_least 8 6 2] == 0 } { From patchwork Tue Aug 20 17:10:32 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 96176 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 937053870882 for ; Tue, 20 Aug 2024 17:12:13 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id AA06D386D61E for ; Tue, 20 Aug 2024 17:10:55 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org AA06D386D61E Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org AA06D386D61E Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724173861; cv=none; b=INkI1PR0J/ff/AAsqdSVjqlIUsjlkK4/3WfUMWm+ik7Vq/Vi2ED8d3jHEIX8VtOVxhRe1y9bGaQpacSJ3ofqn0ytwki+evn5fRwZSO6XfdH+Z/pDSNVGmZ9Gw09J6O6sVLMk6iaeRLn0Sey+w9CTpG1MuAKbCy+xNNuMTm56xu4= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724173861; c=relaxed/simple; bh=0jWGYa5grhBc9QRT4m8b3YqIOMq5fH4uELZ3pPNVI54=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=Vn7EgETgcr2o7KSMufradzDxhAdwUyXb6iGAGSQbPmSbyq5kskk5GHebx7+ON6oqmKnT8uQXWugXOjNgUyKMcajR6h5kVNbaiu/9HyQ6vpTWjCmnwRpDzkWlI3yiDS4lzZhM9fuj/rpXaaHrFCRAPapDUB/fKL+0jARgtUjhf64= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1724173855; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=tOWAypyb+tp0fbmDb3iik9RQfCnnNL2rmhBBGefdwIs=; b=DnuFPJmdFXUyjI37Z3TS8q+zgs1b50vrXBbj+IboTRugvgtWAAnEweCcqN62a9oekpGL4I d0+Jy8eriZLjwE/G2/HslAuh8oZUrRR5SvqWiodB/K+ClXf/UbiBf3Bq7ombeANH8NRasO OLNhUuOCKnAh42lceiTFywX1z0uDMhk= Received: from mail-wr1-f70.google.com (mail-wr1-f70.google.com [209.85.221.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-367-wtpBHUYpMpeVXOS9YDgDcw-1; Tue, 20 Aug 2024 13:10:52 -0400 X-MC-Unique: wtpBHUYpMpeVXOS9YDgDcw-1 Received: by mail-wr1-f70.google.com with SMTP id ffacd0b85a97d-367990b4beeso3369023f8f.2 for ; Tue, 20 Aug 2024 10:10:52 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1724173851; x=1724778651; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=tOWAypyb+tp0fbmDb3iik9RQfCnnNL2rmhBBGefdwIs=; b=m1S2Tj8o3oooAUEiroGjh/MP/kx1OA0xPMfYfE2l96wzpjt1ATsPrYj8LvfMWQvdcO bBzKz29OWjTx55Vl79dT+F7UfuA+P0t3QzFlYbDD1bCbkBw4BDHoEyVHmaeqwmHMAaXg 5m5kkA1YayLHKGZvX+VL/IkSkYAbTY9Yiz+f7SagYtvQJhNrHxSbKt3j+/FZ3PWbE470 goB2u4gV+pPQYR5W4XI3Ui7xX+NrBCb4XWz2v2qIW2G9icQa5t2eWtfyT4wayA6FszPF oLYYQ2c4t8ajcPL/OH0muX3e7y3KfexE2IY3eSTSszksWC9rg+gMEZghAUbIbNtINESw sM8A== X-Gm-Message-State: AOJu0Yx29aJVjrJMIn48OXdyIlU+d+pUJ/eTg6xT7Th99yCXJSRpEwZl HVSl4eBpJznIBxn7UJNuIsvhQ59k0xsqVBD3LhMf+fRKUlo8qleuPftzcQUXRvyZVZLFNmw/8qy G+Gu3AMD6F0c8oQdo2bIB599nfjtkQHcKbkc/CQdRDNutn+ifYThzmn0QYGOV/sar7SUepaFUpE bg71kp8cmr0uLMJpujA+tdWW/03FVy37UQISWAB6d0NHU= X-Received: by 2002:adf:f712:0:b0:371:88a6:80d8 with SMTP id ffacd0b85a97d-371c5fd0997mr1687684f8f.28.1724173850514; Tue, 20 Aug 2024 10:10:50 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHsrIxyvDwSKv2dwmIPTUrFv5rO/PA7xUGe/NIN7l3qTRsoqXPN9byVa27tE4dLV4lszrL20Q== X-Received: by 2002:adf:f712:0:b0:371:88a6:80d8 with SMTP id ffacd0b85a97d-371c5fd0997mr1687656f8f.28.1724173849606; Tue, 20 Aug 2024 10:10:49 -0700 (PDT) Received: from localhost (178.126.90.146.dyn.plus.net. [146.90.126.178]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-37189849a9asm13474236f8f.45.2024.08.20.10.10.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 20 Aug 2024 10:10:47 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv5 02/14] gdb: deprecated filename_completer and associated functions Date: Tue, 20 Aug 2024 18:10:32 +0100 Message-Id: <37c58ee8c1c363597445f0ec96983ddf39d61305.1724173728.git.aburgess@redhat.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-10.3 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org Following on from the previous commit, this commit marks the old unquoted filename completion related functions as deprecated. The aim of doing this is to make it more obvious to someone adding a new command that they should not be using the older unquoted style filename argument handling. I split this change from the previous to make for an easier review. This commit touches more files, but is _just_ function renaming. Check out gdb/completer.{c,h} for what has been renamed. All the other files have just been updated to use the new names. There should be no user visible changes after this commit. --- gdb/auto-load.c | 4 ++-- gdb/breakpoint.c | 4 ++-- gdb/cli/cli-cmds.c | 9 +++++---- gdb/cli/cli-decode.c | 8 ++++---- gdb/cli/cli-dump.c | 6 +++--- gdb/compile/compile.c | 4 ++-- gdb/completer.c | 23 +++++++++++------------ gdb/completer.h | 8 ++++---- gdb/corefile.c | 3 +-- gdb/corelow.c | 3 ++- gdb/dwarf2/index-write.c | 4 ++-- gdb/exec.c | 3 ++- gdb/infcmd.c | 12 ++++++------ gdb/inferior.c | 2 +- gdb/jit.c | 2 +- gdb/record-full.c | 4 ++-- gdb/record.c | 2 +- gdb/skip.c | 2 +- gdb/source.c | 2 +- gdb/symfile.c | 2 +- gdb/target-descriptions.c | 8 ++++---- gdb/tracectf.c | 3 ++- gdb/tracefile-tfile.c | 3 ++- 23 files changed, 62 insertions(+), 59 deletions(-) diff --git a/gdb/auto-load.c b/gdb/auto-load.c index 839be081b3d..e753333b1cd 100644 --- a/gdb/auto-load.c +++ b/gdb/auto-load.c @@ -1629,7 +1629,7 @@ This option has security implications for untrusted inferiors."), See the commands 'set auto-load safe-path' and 'show auto-load safe-path' to\n\ access the current full list setting."), &cmdlist); - set_cmd_completer (cmd, filename_completer); + set_cmd_completer (cmd, deprecated_filename_completer); cmd = add_cmd ("add-auto-load-scripts-directory", class_support, add_auto_load_dir, @@ -1638,7 +1638,7 @@ access the current full list setting."), See the commands 'set auto-load scripts-directory' and\n\ 'show auto-load scripts-directory' to access the current full list setting."), &cmdlist); - set_cmd_completer (cmd, filename_completer); + set_cmd_completer (cmd, deprecated_filename_completer); add_setshow_boolean_cmd ("auto-load", class_maintenance, &debug_auto_load, _("\ diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 17bd627f867..607be7904f9 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -15075,14 +15075,14 @@ This includes all types of breakpoints (breakpoints, watchpoints,\n\ catchpoints, tracepoints). Use the 'source' command in another debug\n\ session to restore them."), &save_cmdlist); - set_cmd_completer (c, filename_completer); + set_cmd_completer (c, deprecated_filename_completer); cmd_list_element *save_tracepoints_cmd = add_cmd ("tracepoints", class_trace, save_tracepoints_command, _("\ Save current tracepoint definitions as a script.\n\ Use the 'source' command in another debug session to restore them."), &save_cmdlist); - set_cmd_completer (save_tracepoints_cmd, filename_completer); + set_cmd_completer (save_tracepoints_cmd, deprecated_filename_completer); c = add_com_alias ("save-tracepoints", save_tracepoints_cmd, class_trace, 0); deprecate_cmd (c, "save tracepoints"); diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c index 92bb8fc2142..58bb62e89d6 100644 --- a/gdb/cli/cli-cmds.c +++ b/gdb/cli/cli-cmds.c @@ -2643,7 +2643,7 @@ The debugger's current working directory specifies where scripts and other\n\ files that can be loaded by GDB are located.\n\ In order to change the inferior's current working directory, the recommended\n\ way is to use the \"set cwd\" command."), &cmdlist); - set_cmd_completer (c, filename_completer); + set_cmd_completer (c, deprecated_filename_completer); add_com ("echo", class_support, echo_command, _("\ Print a constant string. Give string as argument.\n\ @@ -2809,7 +2809,7 @@ the previous command number shown."), = add_com ("shell", class_support, shell_command, _("\ Execute the rest of the line as a shell command.\n\ With no arguments, run an inferior shell.")); - set_cmd_completer (shell_cmd, filename_completer); + set_cmd_completer (shell_cmd, deprecated_filename_completer); add_com_alias ("!", shell_cmd, class_support, 0); @@ -2898,7 +2898,8 @@ you must type \"disassemble 'foo.c'::bar\" and not \"disassemble foo.c:bar\".")) c = add_com ("make", class_support, make_command, _("\ Run the ``make'' program using the rest of the line as arguments.")); - set_cmd_completer (c, filename_completer); + set_cmd_completer (c, deprecated_filename_completer); + c = add_cmd ("user", no_class, show_user, _("\ Show definitions of non-python/scheme user defined commands.\n\ Argument is the name of the user defined command.\n\ @@ -2982,5 +2983,5 @@ Note that the file \"%s\" is read automatically in this way\n\ when GDB is started."), GDBINIT).release (); c = add_cmd ("source", class_support, source_command, source_help_text, &cmdlist); - set_cmd_completer (c, filename_completer); + set_cmd_completer (c, deprecated_filename_completer); } diff --git a/gdb/cli/cli-decode.c b/gdb/cli/cli-decode.c index d9a2ab40575..163012a6bec 100644 --- a/gdb/cli/cli-decode.c +++ b/gdb/cli/cli-decode.c @@ -866,7 +866,7 @@ add_setshow_filename_cmd (const char *name, enum command_class theclass, nullptr, nullptr, set_func, show_func, set_list, show_list); - set_cmd_completer (commands.set, filename_completer); + set_cmd_completer (commands.set, deprecated_filename_completer); return commands; } @@ -890,7 +890,7 @@ add_setshow_filename_cmd (const char *name, command_class theclass, nullptr, show_func, set_list, show_list); - set_cmd_completer (cmds.set, filename_completer); + set_cmd_completer (cmds.set, deprecated_filename_completer); return cmds; } @@ -1015,7 +1015,7 @@ add_setshow_optional_filename_cmd (const char *name, enum command_class theclass nullptr, nullptr, set_func, show_func, set_list, show_list); - set_cmd_completer (commands.set, filename_completer); + set_cmd_completer (commands.set, deprecated_filename_completer); return commands; } @@ -1039,7 +1039,7 @@ add_setshow_optional_filename_cmd (const char *name, command_class theclass, set_func, get_func, nullptr, show_func, set_list,show_list); - set_cmd_completer (cmds.set, filename_completer); + set_cmd_completer (cmds.set, deprecated_filename_completer); return cmds; } diff --git a/gdb/cli/cli-dump.c b/gdb/cli/cli-dump.c index 9b44c6edcf2..2b9307e1de9 100644 --- a/gdb/cli/cli-dump.c +++ b/gdb/cli/cli-dump.c @@ -348,7 +348,7 @@ add_dump_command (const char *name, struct dump_context *d; c = add_cmd (name, all_commands, descr, &dump_cmdlist); - c->completer = filename_completer; + set_cmd_completer (c, deprecated_filename_completer); d = XNEW (struct dump_context); d->func = func; d->mode = FOPEN_WB; @@ -356,7 +356,7 @@ add_dump_command (const char *name, c->func = call_dump_func; c = add_cmd (name, all_commands, descr, &append_cmdlist); - c->completer = filename_completer; + set_cmd_completer (c, deprecated_filename_completer); d = XNEW (struct dump_context); d->func = func; d->mode = FOPEN_AB; @@ -705,6 +705,6 @@ Arguments are FILE OFFSET START END where all except FILE are optional.\n\ OFFSET will be added to the base address of the file (default zero).\n\ If START and END are given, only the file contents within that range\n\ (file relative) will be restored to target memory.")); - c->completer = filename_completer; + set_cmd_completer (c, deprecated_filename_completer); /* FIXME: completers for other commands. */ } diff --git a/gdb/compile/compile.c b/gdb/compile/compile.c index 8896b44a8c4..6c5f33e0c19 100644 --- a/gdb/compile/compile.c +++ b/gdb/compile/compile.c @@ -328,8 +328,8 @@ compile_file_command_completer (struct cmd_list_element *ignore, (tracker, &text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR, group)) return; - word = advance_to_filename_complete_word_point (tracker, text); - filename_completer (ignore, tracker, text, word); + word = advance_to_deprecated_filename_complete_word_point (tracker, text); + deprecated_filename_completer (ignore, tracker, text, word); } /* Handle the input from the 'compile code' command. The diff --git a/gdb/completer.c b/gdb/completer.c index 93eb8db6db0..0e49549a643 100644 --- a/gdb/completer.c +++ b/gdb/completer.c @@ -291,7 +291,7 @@ filename_maybe_quoted_completer (struct cmd_list_element *ignore, filenames. */ static void -filename_completer_handle_brkchars +deprecated_filename_completer_handle_brkchars (struct cmd_list_element *ignore, completion_tracker &tracker, const char *text, const char *word) { @@ -302,14 +302,14 @@ filename_completer_handle_brkchars rl_filename_quoting_desired = 0; tracker.set_use_custom_word_point (true); - word = advance_to_filename_complete_word_point (tracker, text); - filename_completer (ignore, tracker, text, word); + word = advance_to_deprecated_filename_complete_word_point (tracker, text); + deprecated_filename_completer (ignore, tracker, text, word); } /* See completer.h. */ void -filename_completer +deprecated_filename_completer (struct cmd_list_element *ignore, completion_tracker &tracker, const char *text, const char *word) { @@ -499,8 +499,8 @@ advance_to_expression_complete_word_point (completion_tracker &tracker, /* See completer.h. */ const char * -advance_to_filename_complete_word_point (completion_tracker &tracker, - const char *text) +advance_to_deprecated_filename_complete_word_point + (completion_tracker &tracker, const char *text) { const char *brk_chars = gdb_completer_path_break_characters; const char *quote_chars = nullptr; @@ -662,8 +662,8 @@ complete_files_symbols (completion_tracker &tracker, symbol_start, word); /* If text includes characters which cannot appear in a file name, they cannot be asking for completion on files. */ - if (strcspn (text, - gdb_completer_file_name_break_characters) == text_len) + if (strcspn (text, gdb_completer_file_name_break_characters) + == text_len) fn_list = make_source_files_completion_list (text, text); } @@ -713,8 +713,7 @@ complete_source_filenames (const char *text) /* If text includes characters which cannot appear in a file name, the user cannot be asking for completion on files. */ - if (strcspn (text, - gdb_completer_file_name_break_characters) + if (strcspn (text, gdb_completer_file_name_break_characters) == text_len) return make_source_files_completion_list (text, text); @@ -1932,8 +1931,8 @@ default_completer_handle_brkchars (struct cmd_list_element *ignore, completer_handle_brkchars_ftype * completer_handle_brkchars_func_for_completer (completer_ftype *fn) { - if (fn == filename_completer) - return filename_completer_handle_brkchars; + if (fn == deprecated_filename_completer) + return deprecated_filename_completer_handle_brkchars; if (fn == filename_maybe_quoted_completer) return filename_maybe_quoted_completer_handle_brkchars; diff --git a/gdb/completer.h b/gdb/completer.h index c6d064ec9d6..70f123ec32f 100644 --- a/gdb/completer.h +++ b/gdb/completer.h @@ -567,7 +567,7 @@ const char *advance_to_expression_complete_word_point emulating the algorithm readline uses to find the word point. The filenames that are located by this function assume no filename quoting, this function should be paired with filename_completer. */ -extern const char *advance_to_filename_complete_word_point +extern const char *advance_to_deprecated_filename_complete_word_point (completion_tracker &tracker, const char *text); extern void noop_completer (struct cmd_list_element *, @@ -582,9 +582,9 @@ extern void noop_completer (struct cmd_list_element *, accepts quoted filenames and use filename_maybe_quoted_completer, for examples see the 'exec' and 'exec-file' commands. */ -extern void filename_completer (struct cmd_list_element *, - completion_tracker &tracker, - const char *, const char *); +extern void deprecated_filename_completer + (struct cmd_list_element *, completion_tracker &tracker, + const char *, const char *); /* Filename completer for commands where the filename argument can be quoted. This completer also supports completing a list of filenames diff --git a/gdb/corefile.c b/gdb/corefile.c index 96052cfdc6d..f6ec3cd5ca1 100644 --- a/gdb/corefile.c +++ b/gdb/corefile.c @@ -391,9 +391,8 @@ Use FILE as core dump for examining memory and registers.\n\ Usage: core-file FILE\n\ No arg means have no core file. This command has been superseded by the\n\ `target core' and `detach' commands."), &cmdlist); - set_cmd_completer (core_file_cmd, filename_completer); + set_cmd_completer (core_file_cmd, deprecated_filename_completer); - set_show_commands set_show_gnutarget = add_setshow_string_noescape_cmd ("gnutarget", class_files, &gnutarget_string, _("\ diff --git a/gdb/corelow.c b/gdb/corelow.c index 2b7a3550fc1..136f29ea2e8 100644 --- a/gdb/corelow.c +++ b/gdb/corelow.c @@ -1520,7 +1520,8 @@ void _initialize_corelow (); void _initialize_corelow () { - add_target (core_target_info, core_target_open, filename_completer); + add_target (core_target_info, core_target_open, + deprecated_filename_completer); add_cmd ("core-file-backed-mappings", class_maintenance, maintenance_print_core_file_backed_mappings, _("Print core file's file-backed mappings."), diff --git a/gdb/dwarf2/index-write.c b/gdb/dwarf2/index-write.c index 2a50e3b6c2d..ccbaea73380 100644 --- a/gdb/dwarf2/index-write.c +++ b/gdb/dwarf2/index-write.c @@ -1621,8 +1621,8 @@ gdb_save_index_cmd_completer (struct cmd_list_element *ignore, (tracker, &text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, grp)) return; - word = advance_to_filename_complete_word_point (tracker, text); - filename_completer (ignore, tracker, text, word); + word = advance_to_deprecated_filename_complete_word_point (tracker, text); + deprecated_filename_completer (ignore, tracker, text, word); } /* Implementation of the `save gdb-index' command. diff --git a/gdb/exec.c b/gdb/exec.c index f30ed62e4b3..acd9b04337b 100644 --- a/gdb/exec.c +++ b/gdb/exec.c @@ -1119,5 +1119,6 @@ will be loaded as well."), show_exec_file_mismatch_command, &setlist, &showlist); - add_target (exec_target_info, exec_target_open, filename_completer); + add_target (exec_target_info, exec_target_open, + deprecated_filename_completer); } diff --git a/gdb/infcmd.c b/gdb/infcmd.c index 347684a0be1..c999313444a 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -3113,7 +3113,7 @@ Follow this command with any number of args, to be passed to the program."), get_args_value, show_args_command, &setlist, &showlist); - set_cmd_completer (args_set_show.set, filename_completer); + set_cmd_completer (args_set_show.set, deprecated_filename_completer); auto cwd_set_show = add_setshow_string_noescape_cmd ("cwd", class_run, _("\ @@ -3129,7 +3129,7 @@ working directory."), set_cwd_value, get_inferior_cwd, show_cwd_command, &setlist, &showlist); - set_cmd_completer (cwd_set_show.set, filename_completer); + set_cmd_completer (cwd_set_show.set, deprecated_filename_completer); c = add_cmd ("environment", no_class, environment_info, _("\ The environment to give the program, or one variable's value.\n\ @@ -3163,7 +3163,7 @@ This path is equivalent to the $PATH shell variable. It is a list of\n\ directories, separated by colons. These directories are searched to find\n\ fully linked executable files and separately compiled object files as \ needed.")); - set_cmd_completer (c, filename_completer); + set_cmd_completer (c, deprecated_filename_completer); c = add_cmd ("paths", no_class, path_info, _("\ Current search path for finding object files.\n\ @@ -3313,18 +3313,18 @@ Specifying -a and an ignore count simultaneously is an error.")); = add_com ("run", class_run, run_command, _("\ Start debugged program.\n" RUN_ARGS_HELP)); - set_cmd_completer (run_cmd, filename_completer); + set_cmd_completer (run_cmd, deprecated_filename_completer); add_com_alias ("r", run_cmd, class_run, 1); c = add_com ("start", class_run, start_command, _("\ Start the debugged program stopping at the beginning of the main procedure.\n" RUN_ARGS_HELP)); - set_cmd_completer (c, filename_completer); + set_cmd_completer (c, deprecated_filename_completer); c = add_com ("starti", class_run, starti_command, _("\ Start the debugged program stopping at the first instruction.\n" RUN_ARGS_HELP)); - set_cmd_completer (c, filename_completer); + set_cmd_completer (c, deprecated_filename_completer); add_com ("interrupt", class_run, interrupt_command, _("Interrupt the execution of the debugged program.\n\ diff --git a/gdb/inferior.c b/gdb/inferior.c index bc9e5ee58d4..21f37c8313c 100644 --- a/gdb/inferior.c +++ b/gdb/inferior.c @@ -1116,7 +1116,7 @@ as main program.\n\ By default, the new inferior inherits the current inferior's connection.\n\ If -no-connection is specified, the new inferior begins with\n\ no target connection yet.")); - set_cmd_completer (c, filename_completer); + set_cmd_completer (c, deprecated_filename_completer); add_com ("remove-inferiors", no_class, remove_inferior_command, _("\ Remove inferior ID (or list of IDs).\n\ diff --git a/gdb/jit.c b/gdb/jit.c index d4513325190..1a3a033f838 100644 --- a/gdb/jit.c +++ b/gdb/jit.c @@ -1328,7 +1328,7 @@ Usage: jit-reader-load FILE\n\ Try to load file FILE as a debug info reader (and unwinder) for\n\ JIT compiled code. The file is loaded from " JIT_READER_DIR ",\n\ relocated relative to the GDB executable if required.")); - set_cmd_completer (c, filename_completer); + set_cmd_completer (c, deprecated_filename_completer); c = add_com ("jit-reader-unload", no_class, jit_reader_unload_command, _("\ diff --git a/gdb/record-full.c b/gdb/record-full.c index ab854e0133f..a681ef9fe51 100644 --- a/gdb/record-full.c +++ b/gdb/record-full.c @@ -2892,12 +2892,12 @@ _initialize_record_full () _("Restore the execution log from a file.\n\ Argument is filename. File must be created with 'record save'."), &record_full_cmdlist); - set_cmd_completer (record_full_restore_cmd, filename_completer); + set_cmd_completer (record_full_restore_cmd, deprecated_filename_completer); /* Deprecate the old version without "full" prefix. */ c = add_alias_cmd ("restore", record_full_restore_cmd, class_obscure, 1, &record_cmdlist); - set_cmd_completer (c, filename_completer); + set_cmd_completer (c, deprecated_filename_completer); deprecate_cmd (c, "record full restore"); add_setshow_prefix_cmd ("full", class_support, diff --git a/gdb/record.c b/gdb/record.c index d84af60ac71..8bf8a69bf9d 100644 --- a/gdb/record.c +++ b/gdb/record.c @@ -827,7 +827,7 @@ A size of \"unlimited\" means unlimited lines. The default is 10."), Usage: record save [FILENAME]\n\ Default filename is 'gdb_record.PROCESS_ID'."), &record_cmdlist); - set_cmd_completer (c, filename_completer); + set_cmd_completer (c, deprecated_filename_completer); cmd_list_element *record_delete_cmd = add_cmd ("delete", class_obscure, cmd_record_delete, diff --git a/gdb/skip.c b/gdb/skip.c index 72f4efd0e29..3791c29b1e0 100644 --- a/gdb/skip.c +++ b/gdb/skip.c @@ -684,7 +684,7 @@ Ignore a file while stepping.\n\ Usage: skip file [FILE-NAME]\n\ If no filename is given, ignore the current file."), &skiplist); - set_cmd_completer (c, filename_completer); + set_cmd_completer (c, deprecated_filename_completer); c = add_cmd ("function", class_breakpoint, skip_function_command, _("\ Ignore a function while stepping.\n\ diff --git a/gdb/source.c b/gdb/source.c index 0c5c2bad819..b9122c421a0 100644 --- a/gdb/source.c +++ b/gdb/source.c @@ -1915,7 +1915,7 @@ directory in which the source file was compiled into object code.\n\ With no argument, reset the search path to $cdir:$cwd, the default."), &cmdlist); - set_cmd_completer (directory_cmd, filename_completer); + set_cmd_completer (directory_cmd, deprecated_filename_completer); add_setshow_optional_filename_cmd ("directories", class_files, diff --git a/gdb/symfile.c b/gdb/symfile.c index c3cd961c0b9..5054d101cd5 100644 --- a/gdb/symfile.c +++ b/gdb/symfile.c @@ -3846,7 +3846,7 @@ Usage: load [FILE] [OFFSET]\n\ An optional load OFFSET may also be given as a literal address.\n\ When OFFSET is provided, FILE must also be provided. FILE can be provided\n\ on its own."), &cmdlist); - set_cmd_completer (c, filename_completer); + set_cmd_completer (c, deprecated_filename_completer); cmd_list_element *overlay_cmd = add_basic_prefix_cmd ("overlay", class_support, diff --git a/gdb/target-descriptions.c b/gdb/target-descriptions.c index 4bb48fc8bc1..d3ee4e9f8ca 100644 --- a/gdb/target-descriptions.c +++ b/gdb/target-descriptions.c @@ -1760,8 +1760,8 @@ maint_print_c_tdesc_cmd_completer (struct cmd_list_element *ignore, (tracker, &text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR, grp)) return; - word = advance_to_filename_complete_word_point (tracker, text); - filename_completer (ignore, tracker, text, word); + word = advance_to_deprecated_filename_complete_word_point (tracker, text); + deprecated_filename_completer (ignore, tracker, text, word); } /* Implement the maintenance print xml-tdesc command. */ @@ -1945,7 +1945,7 @@ that feature within an already existing target_desc object."), grp); cmd = add_cmd ("xml-tdesc", class_maintenance, maint_print_xml_tdesc_cmd, _("\ Print the current target description as an XML file."), &maintenanceprintlist); - set_cmd_completer (cmd, filename_completer); + set_cmd_completer (cmd, deprecated_filename_completer); cmd = add_cmd ("xml-descriptions", class_maintenance, maintenance_check_xml_descriptions, _("\ @@ -1954,5 +1954,5 @@ Check the target descriptions created in GDB equal the descriptions\n\ created from XML files in the directory.\n\ The parameter is the directory name."), &maintenancechecklist); - set_cmd_completer (cmd, filename_completer); + set_cmd_completer (cmd, deprecated_filename_completer); } diff --git a/gdb/tracectf.c b/gdb/tracectf.c index 282a8250ac1..25a8fe7ead9 100644 --- a/gdb/tracectf.c +++ b/gdb/tracectf.c @@ -1721,6 +1721,7 @@ void _initialize_ctf () { #if HAVE_LIBBABELTRACE - add_target (ctf_target_info, ctf_target_open, filename_completer); + add_target (ctf_target_info, ctf_target_open, + deprecated_filename_completer); #endif } diff --git a/gdb/tracefile-tfile.c b/gdb/tracefile-tfile.c index 4a4c4a2d32a..66769216a6b 100644 --- a/gdb/tracefile-tfile.c +++ b/gdb/tracefile-tfile.c @@ -1120,5 +1120,6 @@ void _initialize_tracefile_tfile (); void _initialize_tracefile_tfile () { - add_target (tfile_target_info, tfile_target_open, filename_completer); + add_target (tfile_target_info, tfile_target_open, + deprecated_filename_completer); } From patchwork Tue Aug 20 17:10:33 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 96175 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 7ED893870860 for ; Tue, 20 Aug 2024 17:11:40 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id B9498386D619 for ; Tue, 20 Aug 2024 17:10:54 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org B9498386D619 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org B9498386D619 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724173857; cv=none; b=p/a5n1Z/5RCjG7LCOCAUAvCdz1A7emkmw/vaXKG5bGK3ep3gSx/V1aKOxmfTtsAuP7UIJ47/gV7tsQ/GAQbV7RVA5yTOeUpVB76S0oFJWlX6TQr50ekZi5GQrNlAfPwbkl3p+Ai2mbe4EDUMThYOnN+X5Nm9gvZD0VzZNdhNrug= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724173857; c=relaxed/simple; bh=nBP3BqVxycwd99sTcr/YhC2/TCFUpkF1fXPdPCpsnxE=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=cOrBUHOiY359tMy//ykzs2ANf9/2FsFq+FlXWgWa1N6Jqh50KQI0bX5WVtouNtwvgHziMJg3LLTdpOZvXur6JiOcdlEMx0uJEc2Mj8UFCYb2ASsYghdq0BThvXCACWvlXrixeN+G1mFPj/+pbDEqP2dXQvXLQcTT78Egzej0TAs= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1724173854; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=w1fvxID55ninqXnnaCFqFKTgVkCiaeCuMYoHm/SozbQ=; b=Sp19qjyhizhfvfmTvI0a0ec2eehgTcRVLqMj5CE0NgBPlVEzONcwCCPzmUGzPk33NsMuO9 op6oU21KPJBp43DO6RutiWTSUQvwfB0xLCeZdGLTp6Hrnf/smCtC9FEiiDCG7TsfFvbprW BOihrih7EZH7YcgEpGO9QwLnMR+7q2M= Received: from mail-wr1-f71.google.com (mail-wr1-f71.google.com [209.85.221.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-479-mdnnDC3vOWOZTG5aci5WTA-1; Tue, 20 Aug 2024 13:10:53 -0400 X-MC-Unique: mdnnDC3vOWOZTG5aci5WTA-1 Received: by mail-wr1-f71.google.com with SMTP id ffacd0b85a97d-3718baf35e0so2891667f8f.1 for ; Tue, 20 Aug 2024 10:10:53 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1724173852; x=1724778652; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=w1fvxID55ninqXnnaCFqFKTgVkCiaeCuMYoHm/SozbQ=; b=gxFJeU8nUKHry0was7bbyG3ZwzJdr5CD5kl2ZUqw9ff0+X/czDwoPlAXsfJH30FJd4 QLSoUiDjey3WFHAYxrHsKxrbyy0NHx0I8x2eTSUSCre0basN8cLAsLdlnYO7t3Ies7zy 9p7kG7f5szA6rKFnTEHYcFTmETyxfSmx1UTiNz8HkK1RHsO5v773PVQKYkUHIryN9kgr 8PHL2cYTA89MteYJkIFrnC360o8/wdM+bBBWGmzcXBOjFDJeaLUhgtfEgPRc/DwWu7U0 bh4ZBbyTyUoqzzpwU8PCH++41fBXJ//Za4isHez4bGZy5meynVf0g+ZfqT2W3aKKo/15 cUzA== X-Gm-Message-State: AOJu0YyNRtglK9xrJ6EwZew5TUH8wkPl16fpG1WKkYRV/Isl6xIZVHOb FADGCWt/CCAqCuhnvwVXCFuuyVvGqGHdKptFL5BGNOMvSA4XM8ePh2A+ylwCrjI0Isw23ziPsYi fauUt56s1d1o5iB5wGjOn1gqB1viPDJ21LapzCGr9LRcIDyuD8p+EL2/gU53pOqvWNi1m7f6TFn h9Egs3Rr8cJXiZko51EUEwqfggDyjesDZuEGrGlzqIWCY= X-Received: by 2002:a05:6000:2ad:b0:366:e64f:b787 with SMTP id ffacd0b85a97d-371c5fa6861mr2249731f8f.8.1724173851563; Tue, 20 Aug 2024 10:10:51 -0700 (PDT) X-Google-Smtp-Source: AGHT+IG2r2jRzkGQ64zim1+VJSrBPL93Lu3Rji67aTtJ0our+c5L6pNyDNpXE+9U74l/vmJfRzQzug== X-Received: by 2002:a05:6000:2ad:b0:366:e64f:b787 with SMTP id ffacd0b85a97d-371c5fa6861mr2249705f8f.8.1724173850781; Tue, 20 Aug 2024 10:10:50 -0700 (PDT) Received: from localhost (178.126.90.146.dyn.plus.net. [146.90.126.178]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-37189897419sm13530336f8f.82.2024.08.20.10.10.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 20 Aug 2024 10:10:50 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv5 03/14] gdb: improve escaping when completing filenames Date: Tue, 20 Aug 2024 18:10:33 +0100 Message-Id: <7af24fb43a666452161b1167cd4645a9e9a5fad4.1724173728.git.aburgess@redhat.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-10.3 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org This improves quoting and escaping when completing filenames for commands that allow filenames to be quoted and escaped. I've struggled a bit trying to split this series into chunks. There's a lot of dependencies between different parts of the completion system, and trying to get this working correctly is pretty messy. This first step is really about implementing 3 readline hooks: rl_char_is_quoted_p - Is a particular character quoted within readline's input buffer? rl_filename_dequoting_function - Remove quoting characters from a filename. rl_filename_quoting_function - Add quoting characters to a filename. See 'info readline' for full details, but with these hooks connected up, readline (on behalf of GDB) should do a better job inserting backslash escapes when completing filenames. There's still a bunch of stuff that doesn't work after this commit, mostly around the 'complete' command which of course doesn't go through readline, so doesn't benefit from all of these new functions yet, I'll add some of this in a later commit. Tab completion is now slightly improved though, it is possible to tab-complete a filename that includes a double or single quote, either in an unquoted string or within a string surrounded by single or double quotes, backslash escaping is used when necessary. There are some additional tests to cover the new functionality. --- gdb/completer.c | 168 +++++++++++++++++- .../gdb.base/filename-completion.exp | 34 ++++ 2 files changed, 199 insertions(+), 3 deletions(-) diff --git a/gdb/completer.c b/gdb/completer.c index 0e49549a643..3ab342dab4f 100644 --- a/gdb/completer.c +++ b/gdb/completer.c @@ -214,6 +214,159 @@ noop_completer (struct cmd_list_element *ignore, { } +/* Return 1 if the character at EINDEX in STRING is quoted (there is an + unclosed quoted string), or if the character at EINDEX is quoted by a + backslash. */ + +static int +gdb_completer_file_name_char_is_quoted (char *string, int eindex) +{ + for (int i = 0; i <= eindex && string[i] != '\0'; ) + { + char c = string[i]; + + if (c == '\\') + { + /* The backslash itself is not quoted. */ + if (i >= eindex) + return 0; + ++i; + /* But the next character is. */ + if (i >= eindex) + return 1; + if (string[i] == '\0') + return 0; + ++i; + continue; + } + else if (strchr (rl_completer_quote_characters, c) != nullptr) + { + /* This assumes that extract_string_maybe_quoted can handle a + string quoted with character C. Currently this is true as the + only characters we put in rl_completer_quote_characters are + single and/or double quotes, both of which + extract_string_maybe_quoted can handle. */ + gdb_assert (c == '"' || c == '\''); + const char *tmp = &string[i]; + (void) extract_string_maybe_quoted (&tmp); + i = tmp - string; + + /* Consider any character within the string we just skipped over + as quoted, though this might not be completely correct; the + opening and closing quotes are not themselves quoted. But so + far this doesn't seem to have caused any issues. */ + if (i >= eindex) + return 1; + } + else + ++i; + } + + return 0; +} + +/* Removing character escaping from FILENAME. QUOTE_CHAR is the quote + character around FILENAME or the null-character if there is no quoting + around FILENAME. */ + +static char * +gdb_completer_file_name_dequote (char *filename, int quote_char) +{ + std::string tmp; + + if (quote_char == '\'') + { + /* There is no backslash escaping within a single quoted string. In + this case we can just return the input string. */ + tmp = filename; + } + else if (quote_char == '"') + { + /* Remove escaping from a double quoted string. */ + for (const char *input = filename; + *input != '\0'; + ++input) + { + if (input[0] == '\\' + && input[1] != '\0' + && strchr ("\"\\", input[1]) != nullptr) + ++input; + tmp += *input; + } + } + else + { + gdb_assert (quote_char == '\0'); + + /* Remove escaping from an unquoted string. */ + for (const char *input = filename; + *input != '\0'; + ++input) + { + /* We allow anything to be escaped in an unquoted string. */ + if (*input == '\\') + { + ++input; + if (*input == '\0') + break; + } + + tmp += *input; + } + } + + return strdup (tmp.c_str ()); +} + +/* Apply character escaping to the file name in TEXT. QUOTE_PTR points to + the quote character surrounding TEXT, or points to the null-character if + there are no quotes around TEXT. MATCH_TYPE will be one of the readline + constants SINGLE_MATCH or MULTI_MATCH depending on if there is one or + many completions. */ + +static char * +gdb_completer_file_name_quote (char *text, int match_type ATTRIBUTE_UNUSED, + char *quote_ptr) +{ + std::string str; + + if (*quote_ptr == '\'') + { + /* There is no backslash escaping permitted within a single quoted + string, so in this case we can just return the input sting. */ + str = text; + } + else if (*quote_ptr == '"') + { + /* Add escaping for a double quoted filename. */ + for (const char *input = text; + *input != '\0'; + ++input) + { + if (strchr ("\"\\", *input) != nullptr) + str += '\\'; + str += *input; + } + } + else + { + gdb_assert (*quote_ptr == '\0'); + + /* Add escaping for an unquoted filename. */ + for (const char *input = text; + *input != '\0'; + ++input) + { + if (strchr (" \t\n\\\"'", *input) + != nullptr) + str += '\\'; + str += *input; + } + } + + return strdup (str.c_str ()); +} + /* Generate filename completions of WORD, storing the completions into TRACKER. This is used for generating completions for commands that only accept unquoted filenames as well as for commands that accept @@ -272,6 +425,7 @@ filename_maybe_quoted_completer_handle_brkchars (gdb_completer_file_name_break_characters); rl_completer_quote_characters = gdb_completer_file_name_quote_characters; + rl_char_is_quoted_p = gdb_completer_file_name_char_is_quoted; } /* Complete on filenames. This is for commands that accepts possibly @@ -1314,6 +1468,7 @@ complete_line_internal_1 (completion_tracker &tracker, completing file names then we can switch to the file name quote character set (i.e., both single- and double-quotes). */ rl_completer_quote_characters = gdb_completer_expression_quote_characters; + rl_char_is_quoted_p = nullptr; /* Decide whether to complete on a list of gdb commands or on symbols. */ @@ -2209,9 +2364,11 @@ completion_tracker::build_completion_result (const char *text, /* Build replacement word, based on the LCD. */ recompute_lowest_common_denominator (); - match_list[0] - = expand_preserving_ws (text, end - start, - m_lowest_common_denominator); + if (rl_filename_completion_desired) + match_list[0] = xstrdup (m_lowest_common_denominator); + else + match_list[0] + = expand_preserving_ws (text, end - start, m_lowest_common_denominator); if (m_lowest_common_denominator_unique) { @@ -3074,6 +3231,11 @@ _initialize_completer () rl_attempted_completion_function = gdb_rl_attempted_completion_function; set_rl_completer_word_break_characters (default_word_break_characters ()); + /* Setup readline globals relating to filename completion. */ + rl_filename_quote_characters = " \t\n\\\"'"; + rl_filename_dequoting_function = gdb_completer_file_name_dequote; + rl_filename_quoting_function = gdb_completer_file_name_quote; + add_setshow_zuinteger_unlimited_cmd ("max-completions", no_class, &max_completions, _("\ Set maximum number of completion candidates."), _("\ diff --git a/gdb/testsuite/gdb.base/filename-completion.exp b/gdb/testsuite/gdb.base/filename-completion.exp index 37629bfbf77..c670637ad61 100644 --- a/gdb/testsuite/gdb.base/filename-completion.exp +++ b/gdb/testsuite/gdb.base/filename-completion.exp @@ -52,6 +52,9 @@ proc setup_directory_tree {} { remote_exec host "touch \"${root}/bb2/dir 2/file 1\"" remote_exec host "touch \"${root}/bb2/dir 2/file 2\"" + remote_exec host "touch \"${root}/bb1/aa\\\"bb\"" + remote_exec host "touch \"${root}/bb1/aa'bb\"" + return $root } @@ -107,6 +110,37 @@ proc run_quoting_and_escaping_tests { root } { "aa cc" } "" "${qc}" false \ "expand filenames containing spaces" + + test_gdb_complete_multiple "$cmd ${qc}${root}/bb1/" \ + "a" "a" { + "aa\"bb" + "aa'bb" + } "" "${qc}" false \ + "expand filenames containing quotes" + } else { + set sp "\\ " + + test_gdb_complete_tab_multiple "$cmd ${qc}${root}/aaa/a" \ + "a${sp}" { + "aa bb" + "aa cc" + } false \ + "expand filenames containing spaces" + + test_gdb_complete_tab_multiple "$cmd ${qc}${root}/bb1/a" \ + "a" { + "aa\"bb" + "aa'bb" + } false \ + "expand filenames containing quotes" + + test_gdb_complete_tab_unique "$cmd ${qc}${root}/bb1/aa\\\"" \ + "$cmd ${qc}${root}/bb1/aa\\\\\"bb${qc}" " " \ + "expand unique filename containing double quotes" + + test_gdb_complete_tab_unique "$cmd ${qc}${root}/bb1/aa\\'" \ + "$cmd ${qc}${root}/bb1/aa\\\\'bb${qc}" " " \ + "expand unique filename containing single quote" } } From patchwork Tue Aug 20 17:10:34 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 96177 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 86679387086D for ; Tue, 20 Aug 2024 17:12:26 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id 5E19638432D5 for ; Tue, 20 Aug 2024 17:10:58 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 5E19638432D5 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 5E19638432D5 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724173862; cv=none; b=fVjOnaGRTb2kSLUAPvMXGK88Z1NRQy711bshdNdydlC/1M/ZJOKNK0elx59mi7CM2JsXoC8WKR47wGulQCM4g/KVtOD3cJX0PRWFZbq61t7nHDUOVoAFhtBiYL+x92VnsB9tkRcqjDq+QEDqGzYtO94E771nbxyPZSfJYR/o+WQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724173862; c=relaxed/simple; bh=RDaAhjypfNdNe8eDSbTI9wXx+XD//HzeUtdkn0NFJMo=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=OtDeqc12knppYPuxwkScNh0sUNoOsXxSYGgPsv4dk0pfYJTCwtpdDuknKA+Q0IeYJ6mOt8gHRmq4I/pLAP5LbJ8/Vv5PPZZZNtMhxNTZ7JsoHX0fOKnscR7frdHj6Vixu8kUr9gi3xUzwJhsK7qz3lJlm7WdOQOqOoCdEEtCCaA= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1724173858; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=aRGVWa3WS311cVktuJOrBNFMS2SEtPY3tuKIoXpXpOc=; b=f44MC01eL90kL6QWUSOcO+NNvMlzNH7ma2XM9HqE4QP7V9trbyEJVWCsYEXY9RTuOLRqCr SVhM5jgta0uk8lx4aDcNEn+YqwRBHNBpYb3ZzmQj4zdr7IWTEggJqeLFdLWYumN3yYkSeK oTAgt6j1M6HVR9BqAi9Wfwd3etnz/00= Received: from mail-wr1-f71.google.com (mail-wr1-f71.google.com [209.85.221.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-281-pIwajB_KMYqi5-SZPDTkJQ-1; Tue, 20 Aug 2024 13:10:56 -0400 X-MC-Unique: pIwajB_KMYqi5-SZPDTkJQ-1 Received: by mail-wr1-f71.google.com with SMTP id ffacd0b85a97d-3718eb22836so3162476f8f.3 for ; Tue, 20 Aug 2024 10:10:55 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1724173853; x=1724778653; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=aRGVWa3WS311cVktuJOrBNFMS2SEtPY3tuKIoXpXpOc=; b=UVfXRyZXnsAJiYf2CZrFBDuLOlOqQKAPrd2LXbPMLBsyGTAvawWvxwnZJa+iXiszbx U/M5x4laCnoMyZ1suZoLQw42F9E+fX3hhv8sJNpvfXN4pVYp5iJf8Kx6Q0Dyh8eoKSeo Ga3+ljlkTRU5AHjDtebwiJpRHn7KqTce3uMGwsxWz85wHwCXDOYu0bY5JBuc1dHLHIEY z1krUmBSs+To3r/lMxQHasZ10WAd2127QBH/KFGpalDWTJdhaMxoTSK0QCXJ3ct7M9hg iiVMHXz6Oqz7ynbwUc9WGpH8H4ArhnlPbAUMakOzPMCbq3uzQA/RWrw6ZNlrxTfZKByM CcyQ== X-Gm-Message-State: AOJu0YxH0dxK0h8QUYQjAqyeJROOgMwUT+giQMqTNyUNJgvFSM4jq71V 2YrQkEjKKnFnfSsvMhHQ/i8IYgF2ExbIcewxhV4EHE0yMf69lwD99U9epWosxiKQBdWmYEHfnoC l0n5RFcibDdvleieaCiAXmksqVJUcV6Cm3lZG7EQa0EZZEe2hLbHZeFGpFRXO/wGoweNH5oT+bR fzPaFGBcDt3/hPYf0J6Tfycds89jY+0RtxYIz1QSsDlDg= X-Received: by 2002:a5d:452b:0:b0:371:8c06:82ea with SMTP id ffacd0b85a97d-371943150a3mr8706527f8f.1.1724173853500; Tue, 20 Aug 2024 10:10:53 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGAhSzoF+jFNZwtM3D91IHrn1+0u2EvkNhrteRMhOYx7qaBDQUayEnfRDYWamx90p8sGIWnIg== X-Received: by 2002:a5d:452b:0:b0:371:8c06:82ea with SMTP id ffacd0b85a97d-371943150a3mr8706495f8f.1.1724173852699; Tue, 20 Aug 2024 10:10:52 -0700 (PDT) Received: from localhost (178.126.90.146.dyn.plus.net. [146.90.126.178]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-429ded1813dsm208695045e9.7.2024.08.20.10.10.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 20 Aug 2024 10:10:51 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess , Tom Tromey Subject: [PATCHv5 04/14] gdb: move display of completion results into completion_result class Date: Tue, 20 Aug 2024 18:10:34 +0100 Message-Id: X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-10.3 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org This commit moves the printing of the 'complete' command results out of the 'complete_command' function. The printing is now done in a new member function 'completion_result::print_matches'. At this point, this is entirely a refactor. The motivation for this refactor is how 'complete' should print the completion of filename arguments. In some cases the filename results need to have escaping added to the output. This escaping needs to be done immediately prior to printing the result as adding too early will result in multiple 'complete' results potentially being sorted incorrectly. See the subsequent commits for more details. There should be no user visible changes after this commit. Approved-By: Tom Tromey --- gdb/cli/cli-cmds.c | 26 +------------------------- gdb/completer.c | 33 +++++++++++++++++++++++++++++++++ gdb/completer.h | 13 +++++++++++++ 3 files changed, 47 insertions(+), 25 deletions(-) diff --git a/gdb/cli/cli-cmds.c b/gdb/cli/cli-cmds.c index 58bb62e89d6..fd8e27735f0 100644 --- a/gdb/cli/cli-cmds.c +++ b/gdb/cli/cli-cmds.c @@ -423,31 +423,7 @@ complete_command (const char *arg, int from_tty) { std::string arg_prefix (arg, word - arg); - if (result.number_matches == 1) - printf_unfiltered ("%s%s\n", arg_prefix.c_str (), result.match_list[0]); - else - { - result.sort_match_list (); - - for (size_t i = 0; i < result.number_matches; i++) - { - printf_unfiltered ("%s%s", - arg_prefix.c_str (), - result.match_list[i + 1]); - if (quote_char) - printf_unfiltered ("%c", quote_char); - printf_unfiltered ("\n"); - } - } - - if (result.number_matches == max_completions) - { - /* ARG_PREFIX and WORD are included in the output so that emacs - will include the message in the output. */ - printf_unfiltered (_("%s%s %s\n"), - arg_prefix.c_str (), word, - get_max_completions_reached_message ()); - } + result.print_matches (arg_prefix, word, quote_char); } } diff --git a/gdb/completer.c b/gdb/completer.c index 3ab342dab4f..370a57e6d7f 100644 --- a/gdb/completer.c +++ b/gdb/completer.c @@ -2504,6 +2504,39 @@ completion_result::reset_match_list () } } +/* See completer.h */ + +void +completion_result::print_matches (const std::string &prefix, + const char *word, int quote_char) +{ + if (this->number_matches == 1) + printf_unfiltered ("%s%s\n", prefix.c_str (), this->match_list[0]); + else + { + this->sort_match_list (); + + for (size_t i = 0; i < this->number_matches; i++) + { + printf_unfiltered ("%s%s", prefix.c_str (), + this->match_list[i + 1]); + if (quote_char) + printf_unfiltered ("%c", quote_char); + printf_unfiltered ("\n"); + } + } + + if (this->number_matches == max_completions) + { + /* PREFIX and WORD are included in the output so that emacs will + include the message in the output. */ + printf_unfiltered (_("%s%s %s\n"), + prefix.c_str (), word, + get_max_completions_reached_message ()); + } + +} + /* Helper for gdb_rl_attempted_completion_function, which does most of the work. This is called by readline to build the match list array and to determine the lowest common denominator. The real matches diff --git a/gdb/completer.h b/gdb/completer.h index 70f123ec32f..e6dc9417932 100644 --- a/gdb/completer.h +++ b/gdb/completer.h @@ -268,6 +268,19 @@ struct completion_result /* Sort the match list. */ void sort_match_list (); + /* Called to display all matches (used by the 'complete' command). + PREFIX is everything before the completion word. WORD is the word + being completed, this is only used if we reach the maximum number of + completions, otherwise, each line of output consists of PREFIX + followed by one of the possible completion words. + + The QUOTE_CHAR is appended after each possible completion word and + should be the quote character that appears before the completion word, + or the null-character if there is no quote before the completion + word. */ + void print_matches (const std::string &prefix, const char *word, + int quote_char); + private: /* Destroy the match list array and its contents. */ void reset_match_list (); From patchwork Tue Aug 20 17:10:35 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 96178 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 95F383841886 for ; Tue, 20 Aug 2024 17:12:33 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id C65523842582 for ; Tue, 20 Aug 2024 17:10:58 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org C65523842582 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org C65523842582 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724173862; cv=none; b=JIy0m+zNWOt4p3JqVNqe/PKQjIF7MQVJ3JuPpSJ+uiMjdyu3TbxNuYt+6tbg6akQ240mgiGhZS4uJAO3AZeKc//g7gwXfF4D63AodbOtDV6Bi+/i2EjW6lJd36dSKkvSwyiZRmQfyysGWfjmbU0zrRAalq5n3jLPCWz+3JHUI1A= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724173862; c=relaxed/simple; bh=fxnBwevF27AhRqv7f06I57/57ZR5jZTPrVFBflIt8HE=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=HfX5WLOcnbqni1F2G7uQ4MSRZwXMNJa/ndTAmfjISRQiC8hodgYvF9n/hgrKexUIqC1gxUJLNtdQ20UTkyTIUBVd3VyNWPB9vyJcuCrcAukTDJMpRw0FR4S6oN/sXoKj5y05W25unUlNN8v1hXRL9fzNZYMG+guNtNT5ntz6S1s= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1724173858; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=JaTb9rSUuwUosKijFLIrofe4FvM80gXNrMdlHMQzeWQ=; b=ZVE3A79ClrVGbI7j8rMNY1BVC/WWGvV4av6xzO3ljZ0t5ceLHoRMU9Z5d+/gPyb+zMVqQv A0KIrj2jkUZsJ2mjUohuEcnShYDXiNMk7zoyDrvm1E7i/KP7nwjP/wfGnkaOYmltz7zZ3F PX6WbTJ5eP7jw3cCQkklZpEqxS7j/ho= Received: from mail-wm1-f71.google.com (mail-wm1-f71.google.com [209.85.128.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-286-ZZ587Cj2OpKJtIYTA0gBNA-1; Tue, 20 Aug 2024 13:10:57 -0400 X-MC-Unique: ZZ587Cj2OpKJtIYTA0gBNA-1 Received: by mail-wm1-f71.google.com with SMTP id 5b1f17b1804b1-428fc34f41bso50050335e9.3 for ; Tue, 20 Aug 2024 10:10:56 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1724173855; x=1724778655; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=JaTb9rSUuwUosKijFLIrofe4FvM80gXNrMdlHMQzeWQ=; b=af9Mpzug7vKfjGHYxJSafEOv/j/vUsbo7g6pM70GfYr8EQGmyZaJ+wOLqa030GaQpj y7fGKy0kOK/AqAGA6T6TWvO8nvXtunjvLG/3aIc81F+j7Ta9n4lj76AO4sSNkx3Q8JEq L1oUR/fA9gqB2OewFxNKLKh9eUlgMRGNSRTq9rW6mszET2Cpw1QpA+TI+aV8M6wXpdEl 6SBdsfaUpnL9bsndNsR4YCfO88fUbGMmmFIszgPJM+IOfVLyB6p1V53NE0n4TXrTpimd 5gtZwcd78F+3OcYkusTCKNw9ykp7glu+2qeUQcotckiV/R/Il1mrloqxMAQa5FaNnV49 ym+A== X-Gm-Message-State: AOJu0YwuQ5DwSpt5BeKGCYQpzq4VueY6/y0zxzCWPQbn/RyUfBejY3G3 sPrPJS9mOR8WizIvxmf1i71wRRBHNjT+0uAyvnltf/p8EMujlthwH3571/v7t0cDNwY1g21LsGd 9tXlc1JfH4Un85mSdzliCX0YSYCjlc9GOrZcl4T3p4TUz2BUyp7j030mNd4MYe6rjJHb7zeU94Y a/fpik1yjiPUdyskCs05wwBp1IR9JYur3a2BJyWe10+hg= X-Received: by 2002:a05:600c:1547:b0:425:7c95:75d0 with SMTP id 5b1f17b1804b1-42abd21f678mr380285e9.18.1724173854530; Tue, 20 Aug 2024 10:10:54 -0700 (PDT) X-Google-Smtp-Source: AGHT+IEOz77mRrmPW4vzZWwoaKfNCGILCAhDj2JGUcbFEdJRsWx0bU6dpdMs7ElXAGbwhflzDKuOhA== X-Received: by 2002:a05:600c:1547:b0:425:7c95:75d0 with SMTP id 5b1f17b1804b1-42abd21f678mr379985e9.18.1724173853647; Tue, 20 Aug 2024 10:10:53 -0700 (PDT) Received: from localhost (178.126.90.146.dyn.plus.net. [146.90.126.178]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3718985a35fsm13595581f8f.59.2024.08.20.10.10.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 20 Aug 2024 10:10:53 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv5 05/14] gdb: simplify completion_result::print_matches Date: Tue, 20 Aug 2024 18:10:35 +0100 Message-Id: X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-10.3 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org Simplify completion_result::print_matches by removing one of the code paths. Now, every time we call ::print_matches we always add the trailing quote. Previously, when using the 'complete' command, if there was only one result then trailing quote was added in ::build_completion_result, but when we had multiple results the trailing quote was added in ::print_matches. As a consequence, ::print_matches had to understand not to add the trailing quote for the single result case. After this commit we don't add the trailing quote in ::build_completion_result, instead ::print_matches always adds the trailing quote, which makes ::print_matches simpler. However, there is a slight problem. When completion is being driven by readline, and not by the 'complete' command, we still need to manually add the trailing quote in the single result case, and as the printing is done by readline we can't add the quote at the time of printing, and so, in ::build_completion_result, we still add the trailing quote, but only when completion is being done for readline. And this does cause a small problem. When completing a filename, if the completion results in a directory name then, when using the 'complete' command, GDB should not be adding a trailing quote. For example, if we have the file /tmp/xxx/foo.c, then what we should see is this: (gdb) complete file '/tmp/xx file 'tmp/xxx/ But what we actually see after this commit is this: (gdb) complete file '/tmp/xx file 'tmp/xxx/' Previously we didn't get the trailing quote in this case, as when there is only a single result, the quote was added in ::build_completion_result, and for filename completion, GDB didn't know what the quote character was in ::build_completion_result, so no quote was added. Now that the trailing quote is always added in ::print_matches, and GDB does know the quote character at this point, so we are now getting the trailing quote, which is not correct. This is a regression, but really, GDB is now broken in a consistent way, if we create the file /tmp/xxa/bar.c, then previously if we did this: (gdb) complete file '/tmp/xx file '/tmp/xxa/' file '/tmp/xxx/' Notice how we get the trailing quote in this case, this is the before patch behaviour, and is also wrong. A later commit will fix things so that the trailing quote is not added in this filename completion case, but for now I'm going to accept this small regression. This change in behaviour caused some failures in one of the completion tests, I've tweaked the test case to expect the trailing quote as part of this commit, but will revert this in a later commit in this series. I've also added an extra test for when the 'complete' command does complete to a single complete filename, in which case the trailing quote is expected. --- gdb/completer.c | 62 +++++++++---------- .../gdb.base/filename-completion.exp | 21 ++++++- 2 files changed, 50 insertions(+), 33 deletions(-) diff --git a/gdb/completer.c b/gdb/completer.c index 370a57e6d7f..2793ce600b9 100644 --- a/gdb/completer.c +++ b/gdb/completer.c @@ -2372,23 +2372,30 @@ completion_tracker::build_completion_result (const char *text, if (m_lowest_common_denominator_unique) { - /* We don't rely on readline appending the quote char as - delimiter as then readline wouldn't append the ' ' after the - completion. */ - char buf[2] = { (char) quote_char () }; - - match_list[0] = reconcat (match_list[0], match_list[0], - buf, (char *) NULL); - match_list[1] = NULL; - - /* If the tracker wants to, or we already have a space at the - end of the match, tell readline to skip appending - another. */ - char *match = match_list[0]; - bool completion_suppress_append - = (suppress_append_ws () - || (match[0] != '\0' - && match[strlen (match) - 1] == ' ')); + bool completion_suppress_append; + + if (from_readline ()) + { + /* We don't rely on readline appending the quote char as + delimiter as then readline wouldn't append the ' ' after the + completion. */ + char buf[2] = { (char) quote_char (), '\0' }; + + match_list[0] = reconcat (match_list[0], match_list[0], buf, + (char *) nullptr); + + /* If the tracker wants to, or we already have a space at the end + of the match, tell readline to skip appending another. */ + char *match = match_list[0]; + completion_suppress_append + = (suppress_append_ws () + || (match[0] != '\0' + && match[strlen (match) - 1] == ' ')); + } + else + completion_suppress_append = false; + + match_list[1] = nullptr; return completion_result (match_list, 1, completion_suppress_append); } @@ -2510,21 +2517,14 @@ void completion_result::print_matches (const std::string &prefix, const char *word, int quote_char) { - if (this->number_matches == 1) - printf_unfiltered ("%s%s\n", prefix.c_str (), this->match_list[0]); - else - { - this->sort_match_list (); + this->sort_match_list (); - for (size_t i = 0; i < this->number_matches; i++) - { - printf_unfiltered ("%s%s", prefix.c_str (), - this->match_list[i + 1]); - if (quote_char) - printf_unfiltered ("%c", quote_char); - printf_unfiltered ("\n"); - } - } + char buf[2] = { (char) quote_char, '\0' }; + size_t off = this->number_matches == 1 ? 0 : 1; + + for (size_t i = 0; i < this->number_matches; i++) + printf_unfiltered ("%s%s%s\n", prefix.c_str (), + this->match_list[i + off], buf); if (this->number_matches == max_completions) { diff --git a/gdb/testsuite/gdb.base/filename-completion.exp b/gdb/testsuite/gdb.base/filename-completion.exp index c670637ad61..e8acd2f85cf 100644 --- a/gdb/testsuite/gdb.base/filename-completion.exp +++ b/gdb/testsuite/gdb.base/filename-completion.exp @@ -81,8 +81,25 @@ proc run_quoting_and_escaping_tests { root } { test_gdb_complete_none "$cmd ${qc}${root}/xx" \ "expand a non-existent filename" - test_gdb_complete_unique "$cmd ${qc}${root}/a" \ - "$cmd ${qc}${root}/aaa/" "" false \ + # The following test is split into separate cmd and tab calls + # so we can xfail the cmd version. The cmd version will add a + # closing quote, it shouldn't be doing this. This will be + # fixed in a later commit. + if { $qc ne "" } { + setup_xfail "*-*-*" + } + test_gdb_complete_cmd_unique "$cmd ${qc}${root}/a" \ + "$cmd ${qc}${root}/aaa/" \ + "expand a unique directory name" + + if { [readline_is_used] } { + test_gdb_complete_tab_unique "$cmd ${qc}${root}/a" \ + "$cmd ${qc}${root}/aaa/" "" \ + "expand a unique directory name" + } + + test_gdb_complete_unique "$cmd ${qc}${root}/cc2" \ + "$cmd ${qc}${root}/cc2${qc}" " " false \ "expand a unique filename" test_gdb_complete_multiple "$cmd ${qc}${root}/" \ From patchwork Tue Aug 20 17:10:36 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 96179 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 950FB3870881 for ; Tue, 20 Aug 2024 17:13:12 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id E968238432EE for ; Tue, 20 Aug 2024 17:10:58 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org E968238432EE Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org E968238432EE Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724173862; cv=none; b=dbMoQePvHQ0tZku00nisP1UMbWihv3mDZLsEg2dB/Bvda6mgnRni+jY/W3H7HgErbM95su1Gx0Yy8iqHJi3blPquw8iIELIr1p/5++cXim0bS41ixlTmTRX8jGbB6aRwYV/pOPda5jJu5skpyoZqDGnLXQ9sWz9fwKpsPdONpWk= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724173862; c=relaxed/simple; bh=EZap3VNs33GIylLeL7vx0hdOzxqTRDXNAAfEeQC576E=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=vuqygUhf+UZLl6Ig75Y5v5ApJB84mEnutU5Msnd+hluQQrMekXYiGd+JqIat+b5mGF8pRd0NVQfUxs71/QV6ODoWcMKAajewogGPDWjE2NjhGwcFammDsNV1nC+5+ZVQ0ARfWZol4JG/Sy+qQeKkwtROzFXvlRnBlKX3pzdn37Q= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1724173858; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=2FCR/Q5GcW1WgSP4zahjjpwCi7YAxUE9YFqmu2NGBtw=; b=FlVdqs09q33an6OWBY69tqdqfxlpkceXiaUoUrlf0RvSioQRWBTxzeMC5YUAbPXeRSotZM oY2CiISjhBI+q9DTb2jSRrq4nerW36be5v6ydvWw7OFWbVzmO8prf42goED6/5nQUg3KlG jhIfUN2Wj/I9JOKxz8YY5MeNJ8vSGWo= Received: from mail-wm1-f69.google.com (mail-wm1-f69.google.com [209.85.128.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-371-KQvgKa8UOE-HtQT-VOXK_A-1; Tue, 20 Aug 2024 13:10:57 -0400 X-MC-Unique: KQvgKa8UOE-HtQT-VOXK_A-1 Received: by mail-wm1-f69.google.com with SMTP id 5b1f17b1804b1-4281b7196bbso49250385e9.0 for ; Tue, 20 Aug 2024 10:10:57 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1724173856; x=1724778656; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=2FCR/Q5GcW1WgSP4zahjjpwCi7YAxUE9YFqmu2NGBtw=; b=RJrjN307ULxoXQM9uQR4H9S+7GIBh8D/q2BuCJz7oIsIgLfwVdLNTCdOJ0vqrC82wj OqkU2zaDFOyUW/eQU9bna3eqoRhOwCDQziyn5F/sOo8jSe5gwPp4txCnXyaQOdmLNOhX iMWc9BotDWU+uaYH2gZgbV6sSA0ZI23jPMdDiKOkZhd4HeiaNpZesO/peX5TYJq6/+VZ Kc7Nb3rCnA3qHvo9qtLVNWMOiZ0a2LkCtcfWChMTzx61SR3pyXenT/Ag7Rmo9YP2sKPN EqdDLsGfh0HRjfLNwkmI7jqUUtpEduXGIH8zAnSXiCQiKTjztVdoUMHHO4eQu0RMTivi qA/A== X-Gm-Message-State: AOJu0YxUolC9G1s2pud1h9m6V2/SIYceN02TDqOV+Wjw1GgF8aiiwb+k h5A+WR0xVjyI+RGOJHe62AWTqw6EoKHKSoTBHozg/vIoB+NdHA4Vs6hT3xPXGaWJ8WvU6/H6LFC tNv8l9aOiVNfyHSOKv8zJuon2/FS+/mQPswBr6gOlolIBdDG2HIqmDw9YU1HBAWUBws5rjxq34t iHZpmVlVtEpWdbfoLVyOel67KsTAve2/JSuBvCWd841nU= X-Received: by 2002:a05:600c:1986:b0:426:6389:94c4 with SMTP id 5b1f17b1804b1-42abd2571fbmr185065e9.37.1724173855588; Tue, 20 Aug 2024 10:10:55 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFAPw4egAgdRbc/LeolyGbI+m7kTUbAPaDkSxBpaTx1pKM7peGDtugXgRqSkpYSkbtoM0RVJg== X-Received: by 2002:a05:600c:1986:b0:426:6389:94c4 with SMTP id 5b1f17b1804b1-42abd2571fbmr184805e9.37.1724173854741; Tue, 20 Aug 2024 10:10:54 -0700 (PDT) Received: from localhost (178.126.90.146.dyn.plus.net. [146.90.126.178]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-429ed7847d7sm148601365e9.31.2024.08.20.10.10.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 20 Aug 2024 10:10:54 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv5 06/14] gdb: add match formatter mechanism for 'complete' command output Date: Tue, 20 Aug 2024 18:10:36 +0100 Message-Id: <3030ef938cae34512c5bf3dca13bb64bd06b9834.1724173728.git.aburgess@redhat.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-10.3 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org This commit solves a problem that existed prior to the previous commit, but the previous commit made more common. When completing a filename with the 'complete' command GDB will always add a trailing quote character, even if the completion is a directory name, in which case it would be better if the trailing quote was not added. Consider: (gdb) complete file '/tmp/xx file '/tmp/xxx/' The completion offered here is really only a partial completion, we've completed up to the end of the next directory name, but, until we have a filename then the completion is not finished and the trailing quote should not be added. This would match the readline behaviour, e.g.: (gdb) file '/tmp/xx (gdb) file '/tmp/xxx/ In this case readline completes the directory name, but doesn't add the trailing quote character. Remember that the 'complete' command is intended for tools like e.g. emacs in order that they can emulate GDB's standard readline completion when implementing a CLI of their own. As such, not adding the trailing quote in this case matches the readline behaviour, and seems like the right way to go. To achieve this, I've added a new function pointer member variable completion_result::m_match_formatter. This contains a pointer to a callback function which is used by the 'complete' command to format each result. The default behaviour of this callback function is to just append the quote character (the character from before the completion string) to the end of the completion result. This matches the current behaviour. However, for filename completion we override the default value of m_match_formatter, this new function checks if the completion result is a directory or not. If the completion result is a directory then the closing quote is not added, instead we add a trailing '/' character. The code to add a trailing '/' character already exists within the filename_completer function. This is no longer needed in this location, instead this code is moved into the formatter callback. Tests are updated to handle the changes in functionality, this removes an xfail added in the previous commit. --- gdb/completer.c | 96 +++++++++++++------ gdb/completer.h | 45 ++++++++- .../gdb.base/filename-completion.exp | 68 +++++++++---- 3 files changed, 158 insertions(+), 51 deletions(-) diff --git a/gdb/completer.c b/gdb/completer.c index 2793ce600b9..d9123e6e74a 100644 --- a/gdb/completer.c +++ b/gdb/completer.c @@ -52,6 +52,8 @@ static const char *completion_find_completion_word (completion_tracker &tracker, static void set_rl_completer_word_break_characters (const char *break_chars); +static bool gdb_path_isdir (const char *filename); + /* See completer.h. */ class completion_tracker::completion_hash_entry @@ -367,6 +369,28 @@ gdb_completer_file_name_quote (char *text, int match_type ATTRIBUTE_UNUSED, return strdup (str.c_str ()); } +/* The function is used to update the completion word MATCH before + displaying it to the user in the 'complete' command output. This + function is only used for formatting filename or directory names. + + This function checks to see if the completion word MATCH is a directory, + in which case a trailing "/" (forward-slash) is added, otherwise + QUOTE_CHAR is added as a trailing quote. + + Return the updated completion word as a string. */ + +static std::string +filename_match_formatter (const char *match, char quote_char) +{ + std::string result (match); + if (gdb_path_isdir (gdb_tilde_expand (match).c_str ())) + result += "/"; + else + result += quote_char; + + return result; +} + /* Generate filename completions of WORD, storing the completions into TRACKER. This is used for generating completions for commands that only accept unquoted filenames as well as for commands that accept @@ -376,6 +400,8 @@ static void filename_completer_generate_completions (completion_tracker &tracker, const char *word) { + tracker.set_match_format_func (filename_match_formatter); + int subsequent_name = 0; while (1) { @@ -394,20 +420,6 @@ filename_completer_generate_completions (completion_tracker &tracker, if (p[strlen (p) - 1] == '~') continue; - /* Readline appends a trailing '/' if the completion is a - directory. If this completion request originated from outside - readline (e.g. GDB's 'complete' command), then we append the - trailing '/' ourselves now. */ - if (!tracker.from_readline ()) - { - std::string expanded = gdb_tilde_expand (p_rl); - struct stat finfo; - const bool isdir = (stat (expanded.c_str (), &finfo) == 0 - && S_ISDIR (finfo.st_mode)); - if (isdir) - p_rl.reset (concat (p_rl.get (), "/", nullptr)); - } - tracker.add_completion (make_completion_match_str (std::move (p_rl), word, word)); } @@ -1688,10 +1700,25 @@ int max_completions = 200; /* Initial size of the table. It automagically grows from here. */ #define INITIAL_COMPLETION_HTAB_SIZE 200 +/* The function is used to update the completion word MATCH before + displaying it to the user in the 'complete' command output. This + default function is used in all cases except those where a completion + function overrides this function by calling set_match_format_func. + + This function returns MATCH with QUOTE_CHAR appended. If QUOTE_CHAR is + the null-character then the returned string will just contain MATCH. */ + +static std::string +default_match_formatter (const char *match, char quote_char) +{ + return std::string (match) + quote_char; +} + /* See completer.h. */ completion_tracker::completion_tracker (bool from_readline) - : m_from_readline (from_readline) + : m_from_readline (from_readline), + m_match_format_func (default_match_formatter) { discard_completions (); } @@ -2397,7 +2424,8 @@ completion_tracker::build_completion_result (const char *text, match_list[1] = nullptr; - return completion_result (match_list, 1, completion_suppress_append); + return completion_result (match_list, 1, completion_suppress_append, + m_match_format_func); } else { @@ -2434,7 +2462,8 @@ completion_tracker::build_completion_result (const char *text, htab_traverse_noresize (m_entries_hash.get (), func, &builder); match_list[builder.index] = NULL; - return completion_result (match_list, builder.index - 1, false); + return completion_result (match_list, builder.index - 1, false, + m_match_format_func); } } @@ -2442,18 +2471,23 @@ completion_tracker::build_completion_result (const char *text, completion_result::completion_result () : match_list (NULL), number_matches (0), - completion_suppress_append (false) + completion_suppress_append (false), + m_match_formatter (default_match_formatter) {} /* See completer.h */ completion_result::completion_result (char **match_list_, size_t number_matches_, - bool completion_suppress_append_) + bool completion_suppress_append_, + match_format_func_t match_formatter_) : match_list (match_list_), number_matches (number_matches_), - completion_suppress_append (completion_suppress_append_) -{} + completion_suppress_append (completion_suppress_append_), + m_match_formatter (match_formatter_) +{ + gdb_assert (m_match_formatter != nullptr); +} /* See completer.h */ @@ -2466,10 +2500,12 @@ completion_result::~completion_result () completion_result::completion_result (completion_result &&rhs) noexcept : match_list (rhs.match_list), - number_matches (rhs.number_matches) + number_matches (rhs.number_matches), + m_match_formatter (rhs.m_match_formatter) { rhs.match_list = NULL; rhs.number_matches = 0; + rhs.m_match_formatter = default_match_formatter; } /* See completer.h */ @@ -2519,12 +2555,18 @@ completion_result::print_matches (const std::string &prefix, { this->sort_match_list (); - char buf[2] = { (char) quote_char, '\0' }; size_t off = this->number_matches == 1 ? 0 : 1; for (size_t i = 0; i < this->number_matches; i++) - printf_unfiltered ("%s%s%s\n", prefix.c_str (), - this->match_list[i + off], buf); + { + gdb_assert (this->m_match_formatter != nullptr); + std::string formatted_match + = this->m_match_formatter (this->match_list[i + off], + (char) quote_char); + + printf_unfiltered ("%s%s\n", prefix.c_str (), + formatted_match.c_str ()); + } if (this->number_matches == max_completions) { @@ -2716,10 +2758,10 @@ gdb_display_match_list_pager (int lines, return 0; } -/* Return non-zero if FILENAME is a directory. +/* Return true if FILENAME is a directory. Based on readline/complete.c:path_isdir. */ -static int +static bool gdb_path_isdir (const char *filename) { struct stat finfo; diff --git a/gdb/completer.h b/gdb/completer.h index e6dc9417932..c18bd16ad26 100644 --- a/gdb/completer.h +++ b/gdb/completer.h @@ -247,12 +247,24 @@ struct completion_match_result struct completion_result { + /* The type of a function that is used to format completion results when + using the 'complete' command. MATCH is the completion word to be + printed, and QUOTE_CHAR is a trailing quote character to (possibly) + add at the end of MATCH. QUOTE_CHAR can be the null-character in + which case no trailing quote should be added. + + Return the possibly modified completion match word which should be + presented to the user. */ + using match_format_func_t = std::string (*) (const char *match, + char quote_char); + /* Create an empty result. */ completion_result (); /* Create a result. */ completion_result (char **match_list, size_t number_matches, - bool completion_suppress_append); + bool completion_suppress_append, + match_format_func_t match_format_func); /* Destroy a result. */ ~completion_result (); @@ -274,10 +286,15 @@ struct completion_result completions, otherwise, each line of output consists of PREFIX followed by one of the possible completion words. - The QUOTE_CHAR is appended after each possible completion word and - should be the quote character that appears before the completion word, - or the null-character if there is no quote before the completion - word. */ + The QUOTE_CHAR is usually appended after each possible completion + word and should be the quote character that appears before the + completion word, or the null-character if there is no quote before + the completion word. + + The QUOTE_CHAR is not always appended to the completion output. For + example, filename completions will not append QUOTE_CHAR if the + completion is a directory name. This is all handled by calling this + function. */ void print_matches (const std::string &prefix, const char *word, int quote_char); @@ -305,6 +322,12 @@ struct completion_result /* Whether readline should suppress appending a whitespace, when there's only one possible completion. */ bool completion_suppress_append; + +private: + /* A function which formats a single completion match ready for display + as part of the 'complete' command output. Different completion + functions can set different formatter functions. */ + match_format_func_t m_match_formatter; }; /* Object used by completers to build a completion match list to hand @@ -441,6 +464,14 @@ class completion_tracker bool from_readline () const { return m_from_readline; } + /* Set the function used to format the completion word before displaying + it to the user to F, this is used by the 'complete' command. */ + void set_match_format_func (completion_result::match_format_func_t f) + { + gdb_assert (f != nullptr); + m_match_format_func = f; + } + private: /* The type that we place into the m_entries_hash hash table. */ @@ -535,6 +566,10 @@ class completion_tracker interactively. The 'complete' command is a way to generate completions not to be displayed by readline. */ bool m_from_readline; + + /* The function used to format the completion word before it is printed + in the 'complete' command output. */ + completion_result::match_format_func_t m_match_format_func; }; /* Return a string to hand off to readline as a completion match diff --git a/gdb/testsuite/gdb.base/filename-completion.exp b/gdb/testsuite/gdb.base/filename-completion.exp index e8acd2f85cf..39f616b45ba 100644 --- a/gdb/testsuite/gdb.base/filename-completion.exp +++ b/gdb/testsuite/gdb.base/filename-completion.exp @@ -58,6 +58,49 @@ proc setup_directory_tree {} { return $root } +# This proc started as a copy of test_gdb_complete_multiple, however, this +# version does some extra work. See the original test_gdb_complete_multiple +# for a description of all the arguments. +# +# When using the 'complete' command with filenames, GDB will add a trailing +# quote for filenames, and a trailing "/" for directory names. As the +# trailing "/" is also added in the tab-completion output the +# COMPLETION_LIST will include the "/" character, but the trailing quote is +# only added when using the 'complete' command. +# +# Pass the trailing quote will be passed as END_QUOTE_CHAR, this proc will +# run the tab completion test, and will then add the trailing quote to those +# entries in COMPLETION_LIST that don't have a trailing "/" before running +# the 'complete' command test. +proc test_gdb_complete_filename_multiple { + cmd_prefix completion_word add_completed_line completion_list + {start_quote_char ""} {end_quote_char ""} {max_completions false} + {testname ""} +} { + if { [readline_is_used] } { + test_gdb_complete_tab_multiple "$cmd_prefix$completion_word" \ + $add_completed_line $completion_list $max_completions $testname + } + + if { $start_quote_char eq "" && $end_quote_char ne "" } { + set updated_completion_list {} + + foreach entry $completion_list { + if {[string range $entry end end] ne "/"} { + set entry $entry$end_quote_char + } + lappend updated_completion_list $entry + } + + set completion_list $updated_completion_list + set end_quote_char "" + } + + test_gdb_complete_cmd_multiple $cmd_prefix $completion_word \ + $completion_list $start_quote_char $end_quote_char $max_completions \ + $testname +} + # Run filename completetion tests for those command that accept quoting and # escaping of the filename argument. # @@ -81,35 +124,22 @@ proc run_quoting_and_escaping_tests { root } { test_gdb_complete_none "$cmd ${qc}${root}/xx" \ "expand a non-existent filename" - # The following test is split into separate cmd and tab calls - # so we can xfail the cmd version. The cmd version will add a - # closing quote, it shouldn't be doing this. This will be - # fixed in a later commit. - if { $qc ne "" } { - setup_xfail "*-*-*" - } - test_gdb_complete_cmd_unique "$cmd ${qc}${root}/a" \ - "$cmd ${qc}${root}/aaa/" \ + test_gdb_complete_unique "$cmd ${qc}${root}/a" \ + "$cmd ${qc}${root}/aaa/" "" false \ "expand a unique directory name" - if { [readline_is_used] } { - test_gdb_complete_tab_unique "$cmd ${qc}${root}/a" \ - "$cmd ${qc}${root}/aaa/" "" \ - "expand a unique directory name" - } - test_gdb_complete_unique "$cmd ${qc}${root}/cc2" \ "$cmd ${qc}${root}/cc2${qc}" " " false \ "expand a unique filename" - test_gdb_complete_multiple "$cmd ${qc}${root}/" \ + test_gdb_complete_filename_multiple "$cmd ${qc}${root}/" \ "b" "b" { "bb1/" "bb2/" } "" "${qc}" false \ "expand multiple directory names" - test_gdb_complete_multiple "$cmd ${qc}${root}/" \ + test_gdb_complete_filename_multiple "$cmd ${qc}${root}/" \ "c" "c" { "cc1/" "cc2" @@ -121,14 +151,14 @@ proc run_quoting_and_escaping_tests { root } { if { $qc ne "" } { set sp " " - test_gdb_complete_multiple "$cmd ${qc}${root}/aaa/" \ + test_gdb_complete_filename_multiple "$cmd ${qc}${root}/aaa/" \ "a" "a${sp}" { "aa bb" "aa cc" } "" "${qc}" false \ "expand filenames containing spaces" - test_gdb_complete_multiple "$cmd ${qc}${root}/bb1/" \ + test_gdb_complete_filename_multiple "$cmd ${qc}${root}/bb1/" \ "a" "a" { "aa\"bb" "aa'bb" From patchwork Tue Aug 20 17:10:37 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 96182 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id AE2443870868 for ; Tue, 20 Aug 2024 17:13:56 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id A7847386D625 for ; Tue, 20 Aug 2024 17:11:00 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org A7847386D625 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org A7847386D625 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724173865; cv=none; b=lZflL7tnAZ0UUWES98fWXWu37rbS2do6q/s1fQ7fjBN7gIxZ5jo47Gm1a4KqZ+zZdZlXHh35MvnxubDM+xV680CKGaVwvV44LEa8I2CisRDh/mfeBU5C8i4GqPXSbm5XE1astR+pehuPAoNvpmZcWtyOWhu5VTB82jm7FuMaB94= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724173865; c=relaxed/simple; bh=IcIT9gmGOTwa1DZeKtUYNzoTmKxP9RUXAgKr9y0WBIM=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=M1gWEuESms/t+CBJHCqffBHi0BnnuA3XYypOg9SCgvylxqUY/XURxkdMLdIicbSRXnPd/0/0ONi+0XCKPRACuWew4zQ2nrTw1r7pG5Tg5KAAi2vWnrbXOd5s+flqsgAXxC2i/dcnWOZik17B2fBj6sTwC1djHhDlOzc9hVY7kFU= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1724173860; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=+1E2MKwOIfdJkRqWdav2uIeCLlCOTF8X/X5aHPFr0HY=; b=Fu2glApaxnhyKe4bNpYIvANEgC545rqLvl3lTnMCNoRZ0vHxzax9pARmfjEqatYDTkNw1q 5+/VfqOiFkwX7E00uhjjozBRPvh/VroJK6U/G+0bA74MFbjqWh1kX61hqrupH5/HvPQe+Y Ly2mVn+Uk67pGaw8Jz0H7eoH1SgHJkY= Received: from mail-wr1-f71.google.com (mail-wr1-f71.google.com [209.85.221.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-586-tCgoEI2iMQadu5-K44u3tA-1; Tue, 20 Aug 2024 13:10:59 -0400 X-MC-Unique: tCgoEI2iMQadu5-K44u3tA-1 Received: by mail-wr1-f71.google.com with SMTP id ffacd0b85a97d-3718d9d9267so2803514f8f.0 for ; Tue, 20 Aug 2024 10:10:59 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1724173857; x=1724778657; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=+1E2MKwOIfdJkRqWdav2uIeCLlCOTF8X/X5aHPFr0HY=; b=AJKYxY0jBrcLKU8qaQ/gd8+VPKrLbfzBdy8pCo3WtOJ4op12N1Tp7m4g/kx7Amk/oD KqeU8YnxxJW+xO/9zvB7X7F+YvMaw6rvisJj9Z9n243YyraObQiNApX8ZVpUsPz6VTCH WCn7pIgsuGZv704omkC17ZiIZyNQeAs1z22vEPAkuAOAli5cdrEuGYuH+ahahMgSI3Rz sA9QwJlF64Wqdxr6UHl/DIoCwLNqTAVk0pXSQi4Z3lHdM9tsfL76WGF/t351Ze9KPNzL BgX88tj8wGw8AuvMa4nBltCCotXAbBlIyqb1Zcytgu59oxY4Rbh7DXrYY8kykkPZ1S0n RnKw== X-Gm-Message-State: AOJu0YynaN23oo50M3idi/ED9zO37LUfBVnWy4ejeTdgB52tPdDZo7dp kTUpbDoLlM+K3XizODRnvD6lBGRFY6+HfkBzkKsCUSbPxzVXv6iEmWRYND0JTH3GAmxoeaPzHNt qYrPrDdWBCzSlsXqRupE5gvDLtHT5UrASR2bObXEigB/LlV+JzjPqmCyYaw2SjDlfJNgaHMhGjS zWHapwkEMQJfFlDHrRq6H1EkIi1Yb+khU0VHzNDVz1z8c= X-Received: by 2002:adf:ec4b:0:b0:366:eade:bfbb with SMTP id ffacd0b85a97d-371946a48camr9016733f8f.46.1724173857126; Tue, 20 Aug 2024 10:10:57 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGzSLB5O2MI7eXs8GA8uU5VRhWlpAIdN/3SYNQrBhnzazhHKxAg8df/gR1AClPBY8opCLoeQw== X-Received: by 2002:adf:ec4b:0:b0:366:eade:bfbb with SMTP id ffacd0b85a97d-371946a48camr9016703f8f.46.1724173856197; Tue, 20 Aug 2024 10:10:56 -0700 (PDT) Received: from localhost (178.126.90.146.dyn.plus.net. [146.90.126.178]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-371898aa393sm13522551f8f.90.2024.08.20.10.10.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 20 Aug 2024 10:10:55 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv5 07/14] gdb: apply escaping to filenames in 'complete' results Date: Tue, 20 Aug 2024 18:10:37 +0100 Message-Id: X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-10.3 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org Building on the mechanism added in the previous commit(s), this commit applies escaping to filenames in the 'complete' command output. Consider a file: /tmp/xxx/aa"bb -- that is a filename that contains a double quote, currently the 'complete' command output looks like this: (gdb) complete file /tmp/xxx/a file /tmp/xxx/aa"bb Notice that the double quote in the output is not escaped. If we passed this same output back to GDB then the double quote will be treated as the start of a string. After this commit then the output looks like this: (gdb) complete file /tmp/xxx/a file /tmp/xxx/aa\"bb The double quote is now escaped. If we feed this output back to GDB then GDB will treat this as a single filename that contains a double quote, exactly what we want. To achieve this I've done a little refactoring, splitting out the core of gdb_completer_file_name_quote, and then added a new call from the filename_match_formatter function. There are updates to the tests to cover this new functionality. --- gdb/completer.c | 98 ++++++++++++++--- .../gdb.base/filename-completion.exp | 100 +++++++++++------- 2 files changed, 144 insertions(+), 54 deletions(-) diff --git a/gdb/completer.c b/gdb/completer.c index d9123e6e74a..7435532954f 100644 --- a/gdb/completer.c +++ b/gdb/completer.c @@ -320,25 +320,24 @@ gdb_completer_file_name_dequote (char *filename, int quote_char) return strdup (tmp.c_str ()); } -/* Apply character escaping to the file name in TEXT. QUOTE_PTR points to - the quote character surrounding TEXT, or points to the null-character if - there are no quotes around TEXT. MATCH_TYPE will be one of the readline - constants SINGLE_MATCH or MULTI_MATCH depending on if there is one or - many completions. */ +/* Apply character escaping to the filename in TEXT and return a newly + allocated buffer containing the possibly updated filename. + + QUOTE_CHAR is the quote character surrounding TEXT, or the + null-character if there are no quotes around TEXT. */ static char * -gdb_completer_file_name_quote (char *text, int match_type ATTRIBUTE_UNUSED, - char *quote_ptr) +gdb_completer_file_name_quote_1 (const char *text, char quote_char) { std::string str; - if (*quote_ptr == '\'') + if (quote_char == '\'') { /* There is no backslash escaping permitted within a single quoted string, so in this case we can just return the input sting. */ str = text; } - else if (*quote_ptr == '"') + else if (quote_char == '"') { /* Add escaping for a double quoted filename. */ for (const char *input = text; @@ -352,7 +351,7 @@ gdb_completer_file_name_quote (char *text, int match_type ATTRIBUTE_UNUSED, } else { - gdb_assert (*quote_ptr == '\0'); + gdb_assert (quote_char == '\0'); /* Add escaping for an unquoted filename. */ for (const char *input = text; @@ -369,6 +368,19 @@ gdb_completer_file_name_quote (char *text, int match_type ATTRIBUTE_UNUSED, return strdup (str.c_str ()); } +/* Apply character escaping to the filename in TEXT. QUOTE_PTR points to + the quote character surrounding TEXT, or points to the null-character if + there are no quotes around TEXT. MATCH_TYPE will be one of the readline + constants SINGLE_MATCH or MULTI_MATCH depending on if there is one or + many completions. */ + +static char * +gdb_completer_file_name_quote (char *text, int match_type ATTRIBUTE_UNUSED, + char *quote_ptr) +{ + return gdb_completer_file_name_quote_1 (text, *quote_ptr); +} + /* The function is used to update the completion word MATCH before displaying it to the user in the 'complete' command output. This function is only used for formatting filename or directory names. @@ -377,12 +389,28 @@ gdb_completer_file_name_quote (char *text, int match_type ATTRIBUTE_UNUSED, in which case a trailing "/" (forward-slash) is added, otherwise QUOTE_CHAR is added as a trailing quote. + When ADD_ESCAPES is true any special characters (e.g. whitespace, + quotes) will be escaped with a backslash. See + gdb_completer_file_name_quote_1 for full details on escaping. When + ADD_ESCAPES is false then no escaping will be added and MATCH (with the + correct trailing character) will be used unmodified. + Return the updated completion word as a string. */ static std::string -filename_match_formatter (const char *match, char quote_char) +filename_match_formatter_1 (const char *match, char quote_char, + bool add_escapes) { - std::string result (match); + std::string result; + if (add_escapes) + { + gdb::unique_xmalloc_ptr quoted_match + (gdb_completer_file_name_quote_1 (match, quote_char)); + result = quoted_match.get (); + } + else + result = match; + if (gdb_path_isdir (gdb_tilde_expand (match).c_str ())) result += "/"; else @@ -391,16 +419,52 @@ filename_match_formatter (const char *match, char quote_char) return result; } +/* The formatting function used to format the results of a 'complete' + command when the result is a filename, but the filename should not have + any escape characters added. Most commands that accept a filename don't + expect the filename to be quoted or to contain escape characters. + + See filename_match_formatter_1 for more argument details. */ + +static std::string +filename_unquoted_match_formatter (const char *match, char quote_char) +{ + return filename_match_formatter_1 (match, quote_char, false); +} + +/* The formatting function used to format the results of a 'complete' + command when the result is a filename, and the filename should have any + special character (e.g. whitespace, quotes) within it escaped with a + backslash. A limited number of commands accept this style of filename + argument. + + See filename_match_formatter_1 for more argument details. */ + +static std::string +filename_maybe_quoted_match_formatter (const char *match, char quote_char) +{ + return filename_match_formatter_1 (match, quote_char, true); +} + /* Generate filename completions of WORD, storing the completions into TRACKER. This is used for generating completions for commands that only accept unquoted filenames as well as for commands that accept - quoted and escaped filenames. */ + quoted and escaped filenames. + + When QUOTE_MATCHES is true TRACKER will be given a match formatter + function which will add escape characters (if needed) in the results. + When QUOTE_MATCHES is false the match formatter provided will not add + any escaping to the results. */ static void filename_completer_generate_completions (completion_tracker &tracker, - const char *word) + const char *word, + bool quote_matches) { - tracker.set_match_format_func (filename_match_formatter); + if (quote_matches) + tracker.set_match_format_func (filename_maybe_quoted_match_formatter); + else + tracker.set_match_format_func (filename_unquoted_match_formatter); int subsequent_name = 0; while (1) @@ -450,7 +514,7 @@ filename_maybe_quoted_completer (struct cmd_list_element *ignore, { filename_maybe_quoted_completer_handle_brkchars (ignore, tracker, text, word); - filename_completer_generate_completions (tracker, word); + filename_completer_generate_completions (tracker, word, true); } /* The brkchars callback used by commands that don't accept quoted @@ -481,7 +545,7 @@ deprecated_filename_completer { gdb_assert (tracker.use_custom_word_point ()); gdb_assert (word != nullptr); - filename_completer_generate_completions (tracker, word); + filename_completer_generate_completions (tracker, word, false); } /* Find the bounds of the current word for completion purposes, and diff --git a/gdb/testsuite/gdb.base/filename-completion.exp b/gdb/testsuite/gdb.base/filename-completion.exp index 39f616b45ba..c852b56f86a 100644 --- a/gdb/testsuite/gdb.base/filename-completion.exp +++ b/gdb/testsuite/gdb.base/filename-completion.exp @@ -82,10 +82,22 @@ proc test_gdb_complete_filename_multiple { $add_completed_line $completion_list $max_completions $testname } - if { $start_quote_char eq "" && $end_quote_char ne "" } { + if { $start_quote_char eq "" } { set updated_completion_list {} foreach entry $completion_list { + # If ENTRY is quoted with double quotes, then any double + # quotes within the entry need to be escaped. + if { $end_quote_char eq "\"" } { + regsub -all "\"" $entry "\\\"" entry + } + + if { $end_quote_char eq "" } { + regsub -all " " $entry "\\ " entry + regsub -all "\"" $entry "\\\"" entry + regsub -all "'" $entry "\\'" entry + } + if {[string range $entry end end] ne "/"} { set entry $entry$end_quote_char } @@ -146,47 +158,61 @@ proc run_quoting_and_escaping_tests { root } { } "" "${qc}" false \ "expand mixed directory and file names" - # GDB does not currently escape word break characters - # (e.g. white space) correctly in unquoted filenames. if { $qc ne "" } { set sp " " - - test_gdb_complete_filename_multiple "$cmd ${qc}${root}/aaa/" \ - "a" "a${sp}" { - "aa bb" - "aa cc" - } "" "${qc}" false \ - "expand filenames containing spaces" - - test_gdb_complete_filename_multiple "$cmd ${qc}${root}/bb1/" \ - "a" "a" { - "aa\"bb" - "aa'bb" - } "" "${qc}" false \ - "expand filenames containing quotes" } else { set sp "\\ " + } + + if { $qc eq "'" } { + set dq "\"" + set dq_re "\"" + } else { + set dq "\\\"" + set dq_re "\\\\\"" + } + + test_gdb_complete_filename_multiple "$cmd ${qc}${root}/bb2/" \ + "d" "ir${sp}" { + "dir 1/" + "dir 2/" + } "" "${qc}" false \ + "expand multiple directory names containing spaces" - test_gdb_complete_tab_multiple "$cmd ${qc}${root}/aaa/a" \ - "a${sp}" { - "aa bb" - "aa cc" - } false \ - "expand filenames containing spaces" - - test_gdb_complete_tab_multiple "$cmd ${qc}${root}/bb1/a" \ - "a" { - "aa\"bb" - "aa'bb" - } false \ - "expand filenames containing quotes" - - test_gdb_complete_tab_unique "$cmd ${qc}${root}/bb1/aa\\\"" \ - "$cmd ${qc}${root}/bb1/aa\\\\\"bb${qc}" " " \ - "expand unique filename containing double quotes" - - test_gdb_complete_tab_unique "$cmd ${qc}${root}/bb1/aa\\'" \ - "$cmd ${qc}${root}/bb1/aa\\\\'bb${qc}" " " \ + test_gdb_complete_filename_multiple "$cmd ${qc}${root}/aaa/" \ + "a" "a${sp}" { + "aa bb" + "aa cc" + } "" "${qc}" false \ + "expand filenames containing spaces" + + test_gdb_complete_filename_multiple "$cmd ${qc}${root}/bb1/" \ + "a" "a" { + "aa\"bb" + "aa'bb" + } "" "${qc}" false \ + "expand filenames containing quotes" + + test_gdb_complete_tab_unique "$cmd ${qc}${root}/bb1/aa${dq}" \ + "$cmd ${qc}${root}/bb1/aa${dq_re}bb${qc}" " " \ + "expand unique filename containing double quotes" + + # It is not possible to include a single quote character + # within a single quoted string. However, GDB does not do + # anything smart if a user tries to do this. Avoid testing + # this case. Maybe in the future we'll figure a way to avoid + # this situation. + if { $qc ne "'" } { + if { $qc eq "" } { + set sq "\\'" + set sq_re "\\\\'" + } else { + set sq "'" + set sq_re "'" + } + + test_gdb_complete_tab_unique "$cmd ${qc}${root}/bb1/aa${sq}" \ + "$cmd ${qc}${root}/bb1/aa${sq_re}bb${qc}" " " \ "expand unique filename containing single quote" } } From patchwork Tue Aug 20 17:10:38 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 96180 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 103BB3870876 for ; Tue, 20 Aug 2024 17:13:22 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id 0ADB5386D626 for ; Tue, 20 Aug 2024 17:11:02 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 0ADB5386D626 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 0ADB5386D626 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724173865; cv=none; b=HtVH1S8WzeSZgVuw9Ri9HbFYwN4B816mqzJLMhrXv6wRrcFBsTIZ2WprNmBYyCXdAJ0Tvs351QBpqdsehEifHxQigJ6AE+rQudbwYINbA7TsuO7J9lok1HsOPYJCEkqsDIPhmy3wJFCiqrVivz4YON89f06Gq/iZf1M20LPrp1o= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724173865; c=relaxed/simple; bh=Y1BK1YTWLB+3Wq0yZQHIeSkYh6+SW46mhkY++yJaoHM=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=mM2Lag+qu8ZTBy18F6dgPKbqPlt7m9QS1tfdhqnKn88wBh+yIZP5G11g9IpYJUv8nutu7GfleJGYOT9kmORI2S7C3NbAtWPwAlW/CHXsSDjxTEjVYdRahkWv4pK879hqwyk98FtbgWC9KDCDaGx/CKxDnyTePO2Vtg+B4zjM37s= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1724173861; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=2C9kaht8TLdDxuQFRpod2aIst83s/C5QJqbY0nylrFM=; b=LyEramf3xYxxvsj/LlpOGXfLDJuNyPjiu75kSWcwBwfXaZUKns+Vy+MflKbvVNLwOPf8f9 9mMqrvTs/it1L1zmHOY8rnBzdaMyDIYmFep/Y3ylRPXIRfk1WlpVcgFi5w8L+jFILNrwxi VsP0fM+yu0GyQf+CHCDms0V6hT1PHhs= Received: from mail-wr1-f72.google.com (mail-wr1-f72.google.com [209.85.221.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-252-xMxCfxh4M565ejbQntqWmQ-1; Tue, 20 Aug 2024 13:11:00 -0400 X-MC-Unique: xMxCfxh4M565ejbQntqWmQ-1 Received: by mail-wr1-f72.google.com with SMTP id ffacd0b85a97d-371b187634fso1207352f8f.0 for ; Tue, 20 Aug 2024 10:10:59 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1724173858; x=1724778658; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=2C9kaht8TLdDxuQFRpod2aIst83s/C5QJqbY0nylrFM=; b=cArQNWDJDfmp33HkgNAZLr1lknmDLm6Y7E+DsHxtKbt/9AEhpr87b/sKY3pSA7bzjV 5/3Are2wDlEeIhtSTsX7NOYj8csTTz/L3HJBjHfsb8xAGCCo5ZN9ziuvYtXQMBZ8u9B2 oYF7U2zs59XZFx7MdgTnNBNllyW96zPYGGnrqcolP4sLAwo9JoA39De+ipdRfc0j8rTO c0v8rl619KEBxfm008kwTcQ9m0DJgcD0QgDajQinQwVWurcPjf82iEWIKtUAtbs4T4ov r0/JifEN4OulsUuVcupMHnWvfMV0RFIhZCCfzvN2Fpxvd40yc4CNlThJfRyYMaBU3NVR naFQ== X-Gm-Message-State: AOJu0YzZVtP4cG5qu5jbLgta/FR7pO5HHlG8B4L9sS3T8Fm13lok4rEn tXNo6Am4VgRDzV4Yp2QW3/BoiWByXmrJd7YJi+2L9gPadjeknjW+utKSEZ1zSZC3FEkV65gZl47 iSoyUOi5aNsvB1ooRCCS39O+telXBWqT2fvJb0OJZ4H6eCL34O/XZnViUpIFCoFs4CJMmiHrO7K oE0OuF79LOqm5ZX4mIsi9+d6RktFs3IQQWWcO/VY0txjg= X-Received: by 2002:adf:efce:0:b0:367:8e52:3bb9 with SMTP id ffacd0b85a97d-371c4aa86b2mr1833799f8f.22.1724173858234; Tue, 20 Aug 2024 10:10:58 -0700 (PDT) X-Google-Smtp-Source: AGHT+IH4Coia9XHBw99a7o6ptfs1S3YXNUnUVuqUfhCo6nfNkf3XW4dPI3WQcmhVB04+dETc6XYXuw== X-Received: by 2002:adf:efce:0:b0:367:8e52:3bb9 with SMTP id ffacd0b85a97d-371c4aa86b2mr1833769f8f.22.1724173857316; Tue, 20 Aug 2024 10:10:57 -0700 (PDT) Received: from localhost (178.126.90.146.dyn.plus.net. [146.90.126.178]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-371898aa496sm13516513f8f.89.2024.08.20.10.10.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 20 Aug 2024 10:10:57 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv5 08/14] gdb: improve gdb_rl_find_completion_word for quoted words Date: Tue, 20 Aug 2024 18:10:38 +0100 Message-Id: <507745547e4ce44b1bcc60a6860b4a9590eeb88b.1724173728.git.aburgess@redhat.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-10.3 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org The function gdb_rl_find_completion_word is very similar to the readline function _rl_find_completion_word, but was either an older version of that function, or was trimmed when copying to remove code which was considered unnecessary. We maintain this copy because the _rl_find_completion_word function is not part of the public readline API, and we need to replicate the functionality of that function as part of the 'complete' command. Within gdb_rl_find_completion_word when looking for the completion word, if we don't find a unclosed quoted string (which would become the completion word) then we scan backwards looking for a word break character. For example, given: (gdb) complete file /tmp/foo There is no unclosed quoted string so we end up scanning backwards from the end looking for a word break character. In this case the space after 'file' and before '/tmp/foo' is found, so '/tmp/foo' becomes the completion word. However, given this: (gdb) complete file /tmp/foo\" There is still no unclosed quoted string, however, when we can backwards the '"' (double quotes) are treated as a word break character, and so we end up using the empty string as the completion word. The readline function _rl_find_completion_word avoids this mistake by using the rl_char_is_quoted_p hook. This function will return true for the double quote character as it is preceded by a backslash. An earlier commit in this series supplied a rl_char_is_quoted_p function for the filename completion case, however, gdb_rl_find_completion_word doesn't call rl_char_is_quoted_p so this doesn't help for the 'complete' case. In this commit I've copied the code to call rl_char_is_quoted_p from _rl_find_completion_word into gdb_rl_find_completion_word. This half solves the problem. In the case: (gdb) complete file /tmp/foo\" We do now try to complete on the string '/tmp/foo\"', however, when we reach filename_completer we call back into readline to actually perform filename completion. However, at this point the WORD variable points to a string that still contains the backslash. The backslash isn't part of the actual filename, that's just an escape character. Our expectation is that readline will remove the backslash when looking for matching filenames. However, readline contains an optimisation to avoid unnecessary work trying to remove escape characters. The readline variable rl_completion_found_quote is set in the readline function gen_completion_matches before the generation of completion matches. This variable is set to true (non-zero) if there is (or might be) escape characters within the completion word. The function rl_filename_completion_function, which generates the filename matches, only removes escape characters when rl_completion_found_quote is true. When GDB generates completions through readline (e.g. tab completion) then rl_completion_found_quote is set correctly. But when we use the 'complete' command we don't pass through readline, and so gen_completion_matches is never called and rl_completion_found_quote is not set. In this case when we call rl_filename_completion_function readline doesn't remove the escapes from the completion word, and so in our case above, readline looks for completions of the exact filename '/tmp/foo\"', that is, the filename including the backslash. To work around this problem I've added a new flag to our function gdb_rl_find_completion_word which is set true when we find any quoting or escaping. This matches what readline does. Then in the 'complete' function we can set rl_completion_found_quote prior to generating completion matches. With this done the 'complete' command now works correctly when trying to complete filenames that contain escaped word break characters. The tests have been updated accordingly. --- gdb/completer.c | 62 ++++++++++++++++--- .../gdb.base/filename-completion.exp | 12 ++-- 2 files changed, 56 insertions(+), 18 deletions(-) diff --git a/gdb/completer.c b/gdb/completer.c index 7435532954f..b0e999ef514 100644 --- a/gdb/completer.c +++ b/gdb/completer.c @@ -48,7 +48,8 @@ /* Forward declarations. */ static const char *completion_find_completion_word (completion_tracker &tracker, const char *text, - int *quote_char); + int *quote_char, + bool *found_any_quoting); static void set_rl_completer_word_break_characters (const char *break_chars); @@ -560,7 +561,9 @@ deprecated_filename_completer boundaries of the current word. QC, if non-null, is set to the opening quote character if we found an unclosed quoted substring, '\0' otherwise. DP, if non-null, is set to the value of the - delimiter character that caused a word break. */ + delimiter character that caused a word break. FOUND_ANY_QUOTING, if + non-null, is set to true if we found any quote characters (single or + double quotes, or a backslash) while finding the completion word. */ struct gdb_rl_completion_word_info { @@ -571,7 +574,7 @@ struct gdb_rl_completion_word_info static const char * gdb_rl_find_completion_word (struct gdb_rl_completion_word_info *info, - int *qc, int *dp, + int *qc, int *dp, bool *found_any_quoting, const char *line_buffer) { int scan, end, delimiter, pass_next, isbrk; @@ -583,6 +586,8 @@ gdb_rl_find_completion_word (struct gdb_rl_completion_word_info *info, the empty string. */ if (point == 0) { + if (found_any_quoting != nullptr) + *found_any_quoting = false; if (qc != NULL) *qc = '\0'; if (dp != NULL) @@ -593,6 +598,7 @@ gdb_rl_find_completion_word (struct gdb_rl_completion_word_info *info, end = point; delimiter = 0; quote_char = '\0'; + bool found_quote = false; brkchars = info->word_break_characters; @@ -618,6 +624,7 @@ gdb_rl_find_completion_word (struct gdb_rl_completion_word_info *info, if (quote_char != '\'' && line_buffer[scan] == '\\') { pass_next = 1; + found_quote = true; continue; } @@ -638,6 +645,7 @@ gdb_rl_find_completion_word (struct gdb_rl_completion_word_info *info, /* Found start of a quoted substring. */ quote_char = line_buffer[scan]; point = scan + 1; + found_quote = true; } } } @@ -651,8 +659,22 @@ gdb_rl_find_completion_word (struct gdb_rl_completion_word_info *info, { scan = line_buffer[point]; - if (strchr (brkchars, scan) != 0) - break; + if (strchr (brkchars, scan) == 0) + continue; + + /* Call the application-specific function to tell us whether + this word break character is quoted and should be skipped. + The const_cast is needed here to comply with the readline + API. The only function we register for rl_char_is_quoted_p + treats the input buffer as 'const', so we're OK. */ + if (rl_char_is_quoted_p != nullptr && found_quote + && (*rl_char_is_quoted_p) (const_cast (line_buffer), + point)) + continue; + + /* Convoluted code, but it avoids an n^2 algorithm with calls + to char_is_quoted. */ + break; } } @@ -676,6 +698,8 @@ gdb_rl_find_completion_word (struct gdb_rl_completion_word_info *info, } } + if (found_any_quoting != nullptr) + *found_any_quoting = found_quote; if (qc != NULL) *qc = quote_char; if (dp != NULL) @@ -702,7 +726,7 @@ advance_to_completion_word (completion_tracker &tracker, int delimiter; const char *start - = gdb_rl_find_completion_word (&info, NULL, &delimiter, text); + = gdb_rl_find_completion_word (&info, nullptr, &delimiter, nullptr, text); tracker.advance_custom_word_point_by (start - text); @@ -775,7 +799,8 @@ complete_nested_command_line (completion_tracker &tracker, const char *text) int quote_char = '\0'; const char *word = completion_find_completion_word (tracker, text, - "e_char); + "e_char, + nullptr); if (tracker.use_custom_word_point ()) { @@ -1992,8 +2017,11 @@ complete (const char *line, char const **word, int *quote_char) try { + bool found_any_quoting = false; + *word = completion_find_completion_word (tracker_handle_brkchars, - line, quote_char); + line, quote_char, + &found_any_quoting); /* Completers that provide a custom word point in the handle_brkchars phase also compute their completions then. @@ -2003,6 +2031,12 @@ complete (const char *line, char const **word, int *quote_char) tracker = &tracker_handle_brkchars; else { + /* Setting this global matches what readline does within + gen_completion_matches. We need this set correctly in case + our completion function calls back into readline to perform + completion (e.g. filename_completer does this). */ + rl_completion_found_quote = found_any_quoting; + complete_line (tracker_handle_completions, *word, line, strlen (line)); tracker = &tracker_handle_completions; } @@ -2280,7 +2314,7 @@ gdb_completion_word_break_characters () noexcept static const char * completion_find_completion_word (completion_tracker &tracker, const char *text, - int *quote_char) + int *quote_char, bool *found_any_quoting) { size_t point = strlen (text); @@ -2290,6 +2324,13 @@ completion_find_completion_word (completion_tracker &tracker, const char *text, { gdb_assert (tracker.custom_word_point () > 0); *quote_char = tracker.quote_char (); + /* This isn't really correct, we're ignoring the case where we found + a backslash escaping a character. However, this isn't an issue + right now as we only rely on *FOUND_ANY_QUOTING being set when + performing filename completion, which doesn't go through this + path. */ + if (found_any_quoting != nullptr) + *found_any_quoting = *quote_char != '\0'; return text + tracker.custom_word_point (); } @@ -2299,7 +2340,8 @@ completion_find_completion_word (completion_tracker &tracker, const char *text, info.quote_characters = rl_completer_quote_characters; info.basic_quote_characters = rl_basic_quote_characters; - return gdb_rl_find_completion_word (&info, quote_char, NULL, text); + return gdb_rl_find_completion_word (&info, quote_char, nullptr, + found_any_quoting, text); } /* See completer.h. */ diff --git a/gdb/testsuite/gdb.base/filename-completion.exp b/gdb/testsuite/gdb.base/filename-completion.exp index c852b56f86a..a4b411c1c67 100644 --- a/gdb/testsuite/gdb.base/filename-completion.exp +++ b/gdb/testsuite/gdb.base/filename-completion.exp @@ -166,10 +166,8 @@ proc run_quoting_and_escaping_tests { root } { if { $qc eq "'" } { set dq "\"" - set dq_re "\"" } else { set dq "\\\"" - set dq_re "\\\\\"" } test_gdb_complete_filename_multiple "$cmd ${qc}${root}/bb2/" \ @@ -193,8 +191,8 @@ proc run_quoting_and_escaping_tests { root } { } "" "${qc}" false \ "expand filenames containing quotes" - test_gdb_complete_tab_unique "$cmd ${qc}${root}/bb1/aa${dq}" \ - "$cmd ${qc}${root}/bb1/aa${dq_re}bb${qc}" " " \ + test_gdb_complete_unique "$cmd ${qc}${root}/bb1/aa${dq}" \ + "$cmd ${qc}${root}/bb1/aa${dq}bb${qc}" " " false \ "expand unique filename containing double quotes" # It is not possible to include a single quote character @@ -205,14 +203,12 @@ proc run_quoting_and_escaping_tests { root } { if { $qc ne "'" } { if { $qc eq "" } { set sq "\\'" - set sq_re "\\\\'" } else { set sq "'" - set sq_re "'" } - test_gdb_complete_tab_unique "$cmd ${qc}${root}/bb1/aa${sq}" \ - "$cmd ${qc}${root}/bb1/aa${sq_re}bb${qc}" " " \ + test_gdb_complete_unique "$cmd ${qc}${root}/bb1/aa${sq}" \ + "$cmd ${qc}${root}/bb1/aa${sq}bb${qc}" " " false \ "expand unique filename containing single quote" } } From patchwork Tue Aug 20 17:10:39 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 96185 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id DC63438438AF for ; Tue, 20 Aug 2024 17:14:25 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id D2B763870849 for ; Tue, 20 Aug 2024 17:11:02 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org D2B763870849 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org D2B763870849 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724173865; cv=none; b=v+VauEo40FNWdtnIXnjpWea0gvhmSXaFdqlFLpsOtQ9lJbfPjsME4B/aoeJv2dapECij51arzLIA8zxj/M5T3X8KXsBzEIIXXNE45snMT3QB5QnsfWDkSOcuOu226f81aSpGiUZpcz9pymCptsLwg+9jhK82BiYDTjQDOaajjv8= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724173865; c=relaxed/simple; bh=gc7CF8aqrfSljFS3I/XtZE0s2W20VlQKZlJYMgKbG5Y=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=KagDCfL7QZjpLvc6iFnuNraXlH7MC25AMEC1nMK+aHuW00nsaMQ8VMqCQvYUfvvnrkA/ho96ORseNM1eexXy0TGpuSF7PUXp6YImTbMJ1VOXN/GtA/iu6yGuees+aOI2hvHVlKnfxHFQtbLiAAHIYEwE8CWNLOP258ESIUCA7SU= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1724173862; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=JpLNou6SmIjyle0dz59EJyqS67m0b9Zt4XKhKWbuNYI=; b=doIsoudm6TSZbWHrugnnEtQsxpImPyGVkKL3u3Fg8BMB/vwERQS429pSNrTvBKIOFKGcDL dLwQKwcwNBeaGCAxXvAsIKSnOKS/T6kWXCIRlvRQzxZ7tJYVJ4SslqLiZ7xM8aOQOawBfn zTAU8EHRR4dJ+ywZlHZ27IkqCc0tjrU= Received: from mail-wr1-f70.google.com (mail-wr1-f70.google.com [209.85.221.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-52-TYMAwF__N_KBVEe6Tiqe4Q-1; Tue, 20 Aug 2024 13:11:01 -0400 X-MC-Unique: TYMAwF__N_KBVEe6Tiqe4Q-1 Received: by mail-wr1-f70.google.com with SMTP id ffacd0b85a97d-367962f0cb0so3257552f8f.1 for ; Tue, 20 Aug 2024 10:11:00 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1724173859; x=1724778659; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=JpLNou6SmIjyle0dz59EJyqS67m0b9Zt4XKhKWbuNYI=; b=iMED06zvvM8VhbFki4ALq9nvV8AJpo8LhyDB78sksRxTPHLJuGRzbQgWBfsRsGoYUY jlajXK1t80aucWO5I/BV0DOfTBmJaJSMKMiWvOnS++BjXKa1oxr1rsbWfF6EnU7ZpM3K FuouSlEjHyZjPs+lCwT/6iYQ59w88OZK/olFVvKsaDCU42zDQSASZxHLGao3En3H8mmT sN6lQp626iu+4tMWHo6zAmKvZkYcJHWeQ0HjSn/4WSuONzolFcLJvDEHPi9TH7vzfyYC A0inhe5myx1m+yaq4ZfXAnUqqRs9BygoQTE+sh4rppI8IWYndQ1MdiPI7Y5N+12YhdW6 G83g== X-Gm-Message-State: AOJu0Yy7Kh4/gaWF241Zu2a3CG3gDETj5tHRkCvf+nJoPlAL/8vIdWqg TVCzm7jCuIi060EoqtsVPwA6GFn3mwjXEjYJA9h9kdwNmCefkgJEJcobbCK/5YHh8mI7etzb73m ntqlU+HwtUggaRT5ocyz1NSaXh/LGV6F4N0k7jCrP5xdQ4GAFh724UHP9QUhlkAgRQODyY6GaUH iqwb5E3KsgK7aY4q346F7zy5au+rFR1sp/XY4RXFR/7d8= X-Received: by 2002:a5d:634c:0:b0:371:8ed7:49e9 with SMTP id ffacd0b85a97d-37194651a96mr10772774f8f.26.1724173859435; Tue, 20 Aug 2024 10:10:59 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHxz4yX/dLngehdPG4R3evKnCco0D5tUfZXbBUmNKX3oiPU3YBv8lu7tJWwpqBz/237swFi+g== X-Received: by 2002:a5d:634c:0:b0:371:8ed7:49e9 with SMTP id ffacd0b85a97d-37194651a96mr10772750f8f.26.1724173858745; Tue, 20 Aug 2024 10:10:58 -0700 (PDT) Received: from localhost (178.126.90.146.dyn.plus.net. [146.90.126.178]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-37189897419sm13530573f8f.82.2024.08.20.10.10.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 20 Aug 2024 10:10:58 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv5 09/14] gdb: implement readline rl_directory_rewrite_hook callback Date: Tue, 20 Aug 2024 18:10:39 +0100 Message-Id: <7246877ddd0af2111d9bce53a0aa147f968bb8fc.1724173728.git.aburgess@redhat.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-10.3 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org Implement the readline rl_directory_rewrite_hook callback function, this is used when readline needs to offer completions from within a directory. The important thing is that this function should remove any escaping, this allows GDB to correctly offer completions in situations like this: (gdb) file /tmp/directory\ with\ spaces/ Note the escaping in 'directory\ with\ spaces'. Without the rl_directory_rewrite_hook callback readline will try to open a directory literally called '/tmp/directory\ with\ spaces' which obviously doesn't exist. There are tests added to cover this new functionality. --- gdb/completer.c | 21 +++++++++++++++++++ .../gdb.base/filename-completion.exp | 12 +++++++++++ 2 files changed, 33 insertions(+) diff --git a/gdb/completer.c b/gdb/completer.c index b0e999ef514..b80649c5260 100644 --- a/gdb/completer.c +++ b/gdb/completer.c @@ -321,6 +321,26 @@ gdb_completer_file_name_dequote (char *filename, int quote_char) return strdup (tmp.c_str ()); } +/* Implement readline's rl_directory_rewrite_hook. Remove any quoting from + the string *DIRNAME,update *DIRNAME, and return non-zero. If *DIRNAME + doesn't need updating then return zero. See readline docs for more + information. */ + +static int +gdb_completer_directory_rewrite (char **dirname) +{ + if (!rl_completion_found_quote) + return 0; + + int quote_char = rl_completion_quote_character; + char *new_dirname + = gdb_completer_file_name_dequote (*dirname, quote_char); + free (*dirname); + *dirname = new_dirname; + + return 1; +} + /* Apply character escaping to the filename in TEXT and return a newly allocated buffer containing the possibly updated filename. @@ -3416,6 +3436,7 @@ _initialize_completer () rl_filename_quote_characters = " \t\n\\\"'"; rl_filename_dequoting_function = gdb_completer_file_name_dequote; rl_filename_quoting_function = gdb_completer_file_name_quote; + rl_directory_rewrite_hook = gdb_completer_directory_rewrite; add_setshow_zuinteger_unlimited_cmd ("max-completions", no_class, &max_completions, _("\ diff --git a/gdb/testsuite/gdb.base/filename-completion.exp b/gdb/testsuite/gdb.base/filename-completion.exp index a4b411c1c67..cf00d007ca7 100644 --- a/gdb/testsuite/gdb.base/filename-completion.exp +++ b/gdb/testsuite/gdb.base/filename-completion.exp @@ -170,6 +170,11 @@ proc run_quoting_and_escaping_tests { root } { set dq "\\\"" } + test_gdb_complete_unique "${cmd} ${qc}${root}/bb2/dir${sp}1/" \ + "${cmd} ${qc}${root}/bb2/dir${sp}1/unique${sp}file${qc}" " " \ + false \ + "expand a unique file name in a directory containing a space" + test_gdb_complete_filename_multiple "$cmd ${qc}${root}/bb2/" \ "d" "ir${sp}" { "dir 1/" @@ -177,6 +182,13 @@ proc run_quoting_and_escaping_tests { root } { } "" "${qc}" false \ "expand multiple directory names containing spaces" + test_gdb_complete_filename_multiple "${cmd} ${qc}${root}/bb2/dir${sp}2/" \ + "f" "ile${sp}" { + "file 1" + "file 2" + } "" "${qc}" false \ + "expand contents of a directory containing a space" + test_gdb_complete_filename_multiple "$cmd ${qc}${root}/aaa/" \ "a" "a${sp}" { "aa bb" From patchwork Tue Aug 20 17:10:40 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 96183 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 88083386D622 for ; Tue, 20 Aug 2024 17:14:00 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id 0A279386D61B for ; Tue, 20 Aug 2024 17:11:04 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 0A279386D61B Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 0A279386D61B Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724173866; cv=none; b=ZCCvTger6YCyRe6TQs+BJPQ7CONMClovAm7Oon8QGsSxPCr9LaTEnqRXFUrdcXsBz9OhdmMs9pdyWSwtYbpcM4EBcv5Y+7R+M4bFyRvFtjAbQ1cuX8CMpzEQiDCwN3H9K3bR8uNZj/W3wdWojWD5PkiInheNwSHfDbcyweetfXg= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724173866; c=relaxed/simple; bh=eAVXMGrEJIrucxg6ccShUBFX17urrAEeIFJy7X3dGs0=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=PIm0a5zMkSDeJ6NJs9rTxHVoyGfng/xT4MiAXCp8dPInaybF0MkytY84D4saoIqRmDSOLOircIOZgqUD4HcVZEbkngwI9rN6/BNdkQA9BpjIif99TBEoocWamvym3MKNi/X4YGfXbJLHvDFIHiMT0Vdj1/2KVQn1UjH7xCOOFE0= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1724173863; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=AgiRYunwb1sqINzabu/hONw5ELu3zFdGmFiZATxPpzI=; b=RYMr42yEIWys5KFaiRzzA/HvDtnkJJYnNc1LEP7chs946fpUsgzaKVCAd1bbkxiUOgsWCj mnOSiP9kUE4Xw4SZAUqcA7htkASzch7trHZeiRPtLIBXjYSFe44pbz89Zl8I/96/ZQg1sY uo0A2FkbpVMjlWb7ClvTbhFzzG3rabI= Received: from mail-wm1-f72.google.com (mail-wm1-f72.google.com [209.85.128.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-639-QIC_5pgaOO6OEV4KrCy2Xg-1; Tue, 20 Aug 2024 13:11:02 -0400 X-MC-Unique: QIC_5pgaOO6OEV4KrCy2Xg-1 Received: by mail-wm1-f72.google.com with SMTP id 5b1f17b1804b1-4280a434147so48754065e9.3 for ; Tue, 20 Aug 2024 10:11:02 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1724173860; x=1724778660; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=AgiRYunwb1sqINzabu/hONw5ELu3zFdGmFiZATxPpzI=; b=Sem8Upj9YcYvGEMYlycXc4ciA+nrHpsRQhkNj6MV0716P/d6fYrFy2PlZRHZaJUojJ IHBKjY7ofsCqlywucwwIcJRVC6A+ZoGAn4vO2INZsSuOZEcZMh5fsz73BGPLxPf8sVk2 MuGa4Svq0xOCpizijV3a1qJI4d+nbKIm6CB/zpFuc4mdcyLp3yRH4nw0kQQ+1zuNrRxb bLXSsjjg90OFFm3zvCHPgXGi4bGAIA9CIGevIp+XPvZ5OPXrSrZgb8fcX+afqFQREnkK ng7xtuBmBggvlS0/2xTz1qf2n87vPMAPd4bhUrJiKLKlHJvW8RaCq2WUt9g3ExUKco3M sWtA== X-Gm-Message-State: AOJu0YzY3xvi3Nw9omncAL8HtDJZYkc7qRtqYqn+k7vCo73d+QhGiefu W+2IiV40D9M2R1X/dWRQl29fj1qbBYxoO/NCjgRzVLp+TPwsFpvBdN23ndWk11lLSCNCLxgJu2W dY8hxkkMuRVHqqANWELTPl7X9t3/2J4UZxUgSKf091soa6o7vU2IYO0nbzxxjzOW/paoE5K+F1H B1os1/hjAFzq6n3ix2UsOJa5XVzPnizEgqNAuF05Keyao= X-Received: by 2002:a05:600c:198f:b0:428:23c8:1e54 with SMTP id 5b1f17b1804b1-42abd23bb28mr331855e9.18.1724173860483; Tue, 20 Aug 2024 10:11:00 -0700 (PDT) X-Google-Smtp-Source: AGHT+IEMmMK5rThzFF0HWihNu68oNFfU6LjwbLdEvjy3Pj2tS8Vh4WKrl1vniEXESpjCuG0UmaPeEQ== X-Received: by 2002:a05:600c:198f:b0:428:23c8:1e54 with SMTP id 5b1f17b1804b1-42abd23bb28mr331625e9.18.1724173859791; Tue, 20 Aug 2024 10:10:59 -0700 (PDT) Received: from localhost (178.126.90.146.dyn.plus.net. [146.90.126.178]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3718984993fsm13528020f8f.31.2024.08.20.10.10.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 20 Aug 2024 10:10:59 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv5 10/14] gdb: new extract_single_filename_arg helper function Date: Tue, 20 Aug 2024 18:10:40 +0100 Message-Id: <176cf23fc8a811802a6e818a5c09ffc3838a990d.1724173728.git.aburgess@redhat.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-10.4 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org This commit is in preparation for the next few commits, this commit adds a new function extract_single_filename_arg. This new function will be used to convert GDB commands that expect a single filename argument to have these commands take a possibly quoted or escaped string. There's no use of the new function in this commit, for that see the following commits. --- gdb/utils.c | 18 ++++++++++++++++++ gdb/utils.h | 14 ++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/gdb/utils.c b/gdb/utils.c index 94310300fb5..07c5d3c5f5b 100644 --- a/gdb/utils.c +++ b/gdb/utils.c @@ -80,6 +80,7 @@ #include "gdbsupport/buildargv.h" #include "pager.h" #include "run-on-main-thread.h" +#include "gdbsupport/gdb_tilde_expand.h" void (*deprecated_error_begin_hook) (void); @@ -3667,6 +3668,23 @@ copy_bitwise (gdb_byte *dest, ULONGEST dest_offset, } } +/* See utils.h. */ + +std::string +extract_single_filename_arg (const char *args) +{ + if (args == nullptr) + return {}; + + std::string filename = extract_string_maybe_quoted (&args); + args = skip_spaces (args); + if (*args != '\0') + error (_("Junk after filename \"%s\": %s"), filename.c_str (), args); + if (!filename.empty ()) + filename = gdb_tilde_expand (filename.c_str ()); + return filename; +} + #if GDB_SELF_TEST static void test_assign_set_return_if_changed () diff --git a/gdb/utils.h b/gdb/utils.h index 90c8012e73b..d69c81ca834 100644 --- a/gdb/utils.h +++ b/gdb/utils.h @@ -371,6 +371,20 @@ assign_return_if_changed (T &lval, const T &val) return true; } +/* ARG is an argument string as passed to a GDB command which is expected + to contain a single, possibly quoted, filename argument. Extract the + filename and return it as a string. If the filename is quoted then the + quotes will have been removed. If the filename is not quoted then any + escaping within the filename will have been removed. + + If there is any content in ARG after the filename then an error will be + thrown complaining about the extra content. + + If there is no filename in ARG, or if ARG is nullptr, then an empty + string will be returned. */ + +extern std::string extract_single_filename_arg (const char *arg); + /* A class that can be used to intercept warnings. A class is used here, rather than a gdb::function_view because it proved difficult to use a function view in conjunction with ATTRIBUTE_PRINTF in a From patchwork Tue Aug 20 17:10:41 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 96181 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 88215384189C for ; Tue, 20 Aug 2024 17:13:32 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id EA870386D622 for ; Tue, 20 Aug 2024 17:11:05 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org EA870386D622 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org EA870386D622 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724173868; cv=none; b=K68KMqBJbABNLS+RAz2fSRzeIxIJH1S+G0Yi0fG+qxIWRVOizlXlNw0dl0Y801XNW1Pq6vedmZtbDGWnr9Dif0+e7ZzBnZvu41shYHlcTD9mQJA2GQc4E9HIv5On2JPTF7hiZQVMfYUXUdpSSKlVghERtLC+qPAle4bVhvSzafc= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724173868; c=relaxed/simple; bh=nFxpyuMfB17zFgF8ol1z05O1rx4ukW7DAIiUGJerwa0=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=pnc/aztuOtBH3HxenelHtmF1eJvjasS7D+kDTUwumBF80R+35krqLidrKOMGXPu16ynYJdo+9C/pJAOMgygjYe5VYnPA1aQsDpSrSNbnC3e5BFJQGnYu1d3XFU2mgwJAX8XzWpUAGpWaYTMvdwxRBI+/y/ShmT95lyyTdFWRvDc= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1724173865; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=IXI7VwVTHwoAEfXwK6Z00UpL3aAM7DLEEwJ88bCciuo=; b=IJQSUbxgdp7tHZ4nTmlh+t4jLb+h14fE3P2KcYMHy+sQ5cgMZltnxOq4dBDiC62IBJNi73 yqlPjz3dYnjKPk1UDmKgWtF6lurFSUIYEaT47/cIeH3BnlNjERKn5hUVNGQ0mu51opQugN wMsrHVB3mlgVtdgdba1PVyTHQORpcE0= Received: from mail-wm1-f70.google.com (mail-wm1-f70.google.com [209.85.128.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-161-ttLNKnH8NNufoq9tWy7ATA-1; Tue, 20 Aug 2024 13:11:04 -0400 X-MC-Unique: ttLNKnH8NNufoq9tWy7ATA-1 Received: by mail-wm1-f70.google.com with SMTP id 5b1f17b1804b1-42820c29a76so50073685e9.2 for ; Tue, 20 Aug 2024 10:11:04 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1724173862; x=1724778662; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=IXI7VwVTHwoAEfXwK6Z00UpL3aAM7DLEEwJ88bCciuo=; b=wSD8WAb76vu0+1+SpKk/68ZQMYTPNLaaInDY8GLHUwXu9+xVGGP34L1APKroWfg8Qn tqTU4n+O+ouXhbhP0xFJMtdBSE4qLDIYSCPO55u13sbMrR4YAOZRRbL7fukzfxEW3jRW NKsWHHOfg2N6aj2xZbhRICSqDYhIPWjADA5S7aemV3BmWjxkAIwK2Jx12uzF+NHVq2lH Zq5AzzkWY4XFtjLcpvXO2Iy2UJBaOHY1XqdVs05E7R9+apWIQhUNQWIyGzacySF2Va7m tGtoY71GZ59bLY77ywWLWV/PKoTk0Z0GQttyNbaApuJStiy2I6kdpFbFElQSnvrpZ1v/ YM1Q== X-Gm-Message-State: AOJu0Yx7ghPgclQY2St3jVmUvh4MS71vR7t8ReSQMEe9VvVa+zrEDGzS dlzePGP59vQLu9bQq5ulP7u3CLz5/Y1EgI7nI6LfQm2uBiQn6RLzpUftYvd41mTBdToQ1g/piOF h+SxaQOP3XPPRdrrU+RAqCWPLLpRjf8etNphDM9SBT4Lmm2dQkiddQKdxBeuok2U7dMcnlAkdEk e98zhbZWqMkYDDqnnP2tM2Q1YTXH0c359BW9vzHPHB5Hc= X-Received: by 2002:a05:600c:1c90:b0:426:647b:1bfc with SMTP id 5b1f17b1804b1-42abd244b11mr225205e9.30.1724173862028; Tue, 20 Aug 2024 10:11:02 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHCKqmXsHMu1KT8pPCdz/+lM6n09euusGOIzWWJRp5pMWAq2hMJqq3dnrLG8fcKGDvGR7FbFg== X-Received: by 2002:a05:600c:1c90:b0:426:647b:1bfc with SMTP id 5b1f17b1804b1-42abd244b11mr224825e9.30.1724173860876; Tue, 20 Aug 2024 10:11:00 -0700 (PDT) Received: from localhost (178.126.90.146.dyn.plus.net. [146.90.126.178]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-429ed650e21sm148489415e9.20.2024.08.20.10.11.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 20 Aug 2024 10:11:00 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv5 11/14] gdb: extend completion of quoted filenames to work in brkchars phase Date: Tue, 20 Aug 2024 18:10:41 +0100 Message-Id: X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-10.4 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org Up to this point filename completion for possibly quoted filenames has always been handled during the second (non-brkchars) phase of completion. This works fine for commands that only want to complete on a single filename argument. In a later commit though I need to perform completion of a quoted filename argument during the first (brkchars) phase of completion. This will allow me to add a custom completer that completes both command options and arguments for a command (remove-symbol-file) that takes a possibly quoted filename argument. This commit doesn't add the remove-symbol-file completer, this commit is just about putting support for that in place. To achieve this I've added the new function advance_to_filename_maybe_quoted_complete_word_point, which is unused in this commit. I've then had to extend some other functions in order to extract the quoting state during the brkchars phase. As this commit doesn't use the new functionality, the important thing at this point is that I've not regressed the existing filename completion (or any of the other completion). The next commit in this series will make use of the new functionality, and will include tests. There should be no user visible changes after this commit. --- gdb/completer.c | 98 +++++++++++++++++++++++++++++++++++++++++-------- gdb/completer.h | 8 ++++ 2 files changed, 91 insertions(+), 15 deletions(-) diff --git a/gdb/completer.c b/gdb/completer.c index b80649c5260..e8f5e7bb577 100644 --- a/gdb/completer.c +++ b/gdb/completer.c @@ -730,13 +730,23 @@ gdb_rl_find_completion_word (struct gdb_rl_completion_word_info *info, /* Find the completion word point for TEXT, emulating the algorithm readline uses to find the word point, using WORD_BREAK_CHARACTERS - as word break characters. */ + as word break characters. + + The output argument *FOUND_ANY_QUOTING is set to true if the completion + word found either has an opening quote, or contains backslash escaping + within it. Otherwise *FOUND_ANY_QUOTING is set to false. + + The output argument *QC is set to the opening quote character for the + completion word that is found, or to the null character if there is no + opening quote. */ static const char * advance_to_completion_word (completion_tracker &tracker, const char *word_break_characters, const char *quote_characters, - const char *text) + const char *text, + bool *found_any_quoting, + int *qc) { gdb_rl_completion_word_info info; @@ -746,7 +756,8 @@ advance_to_completion_word (completion_tracker &tracker, int delimiter; const char *start - = gdb_rl_find_completion_word (&info, nullptr, &delimiter, nullptr, text); + = gdb_rl_find_completion_word (&info, qc, &delimiter, found_any_quoting, + text); tracker.advance_custom_word_point_by (start - text); @@ -767,18 +778,54 @@ advance_to_expression_complete_word_point (completion_tracker &tracker, { const char *brk_chars = current_language->word_break_characters (); const char *quote_chars = gdb_completer_expression_quote_characters; - return advance_to_completion_word (tracker, brk_chars, quote_chars, text); + return advance_to_completion_word (tracker, brk_chars, quote_chars, + text, nullptr, nullptr); } /* See completer.h. */ const char * -advance_to_deprecated_filename_complete_word_point +advance_to_filename_maybe_quoted_complete_word_point (completion_tracker &tracker, const char *text) +{ + const char *brk_chars = gdb_completer_file_name_break_characters; + const char *quote_chars = gdb_completer_file_name_quote_characters; + rl_char_is_quoted_p = gdb_completer_file_name_char_is_quoted; + bool found_any_quoting = false; + int qc; + const char *result + = advance_to_completion_word (tracker, brk_chars, quote_chars, + text, &found_any_quoting, &qc); + rl_completion_found_quote = found_any_quoting ? 1 : 0; + if (qc != '\0') + { + tracker.set_quote_char (qc); + /* If we're completing for readline (not the 'complete' command) then + we want readline to correctly detect the opening quote. The set + of quote characters will have been set during the brkchars phase, + so now we move the word point back by one (so it's pointing at + the quote character) and now readline will correctly spot the + opening quote. For the 'complete' command setting the quote + character in the tracker is enough, so there's no need to move + the word point back here. */ + if (tracker.from_readline ()) + tracker.advance_custom_word_point_by (-1); + } + return result; +} + +/* See completer.h. */ + +const char * +advance_to_deprecated_filename_complete_word_point (completion_tracker &tracker, + const char *text) { const char *brk_chars = gdb_completer_path_break_characters; const char *quote_chars = nullptr; - return advance_to_completion_word (tracker, brk_chars, quote_chars, text); + rl_filename_quoting_desired = 0; + + return advance_to_completion_word (tracker, brk_chars, quote_chars, + text, nullptr, nullptr); } /* See completer.h. */ @@ -2283,7 +2330,21 @@ gdb_completion_word_break_characters_throw () gdb_custom_word_point_brkchars[0] = rl_line_buffer[rl_point]; rl_completer_word_break_characters = gdb_custom_word_point_brkchars; - rl_completer_quote_characters = NULL; + + /* When performing filename completion we have two options, unquoted + filename completion, in which case the quote characters will have + already been set to nullptr, or quoted filename completion in + which case the quote characters will be set to a string of + characters. In this second case we need readline to perform the + check for a quoted string so that it sets its internal notion of + the quote character correctly, this allows readline to correctly + add the trailing quote (if necessary) after completing a + filename. + + For non-filename completion we manually add a trailing quote if + needed, so we clear the quote characters set here. */ + if (!rl_filename_completion_desired) + rl_completer_quote_characters = NULL; /* Clear this too, so that if we're completing a quoted string, readline doesn't consider the quote character a delimiter. @@ -2330,7 +2391,12 @@ gdb_completion_word_break_characters () noexcept handle_brkchars phase (using TRACKER) to figure out the right work break characters for the command in TEXT. QUOTE_CHAR, if non-null, is set to the opening quote character if we found an unclosed quoted substring, - '\0' otherwise. */ + '\0' otherwise. + + The argument *FOUND_ANY_QUOTING is set to true if the completion word is + either surrounded by quotes, or contains any backslash escapes, but is + only set if TRACKER.use_custom_word_point() is false, otherwise + *FOUND_ANY_QUOTING is just set to false. */ static const char * completion_find_completion_word (completion_tracker &tracker, const char *text, @@ -2344,13 +2410,12 @@ completion_find_completion_word (completion_tracker &tracker, const char *text, { gdb_assert (tracker.custom_word_point () > 0); *quote_char = tracker.quote_char (); - /* This isn't really correct, we're ignoring the case where we found - a backslash escaping a character. However, this isn't an issue - right now as we only rely on *FOUND_ANY_QUOTING being set when - performing filename completion, which doesn't go through this - path. */ + /* If use_custom_word_point is set then the completions have already + been calculated, in which case we don't need to have this flag + set correctly, which is lucky as we don't currently have any way + to know if the completion word included any backslash escapes. */ if (found_any_quoting != nullptr) - *found_any_quoting = *quote_char != '\0'; + *found_any_quoting = false; return text + tracker.custom_word_point (); } @@ -2527,7 +2592,10 @@ completion_tracker::build_completion_result (const char *text, { bool completion_suppress_append; - if (from_readline ()) + /* For filename completion we rely on readline to append the closing + quote. While for other types of completion we append the closing + quote here. */ + if (from_readline () && !rl_filename_completion_desired) { /* We don't rely on readline appending the quote char as delimiter as then readline wouldn't append the ' ' after the diff --git a/gdb/completer.h b/gdb/completer.h index c18bd16ad26..44eafc487f7 100644 --- a/gdb/completer.h +++ b/gdb/completer.h @@ -618,6 +618,14 @@ const char *advance_to_expression_complete_word_point extern const char *advance_to_deprecated_filename_complete_word_point (completion_tracker &tracker, const char *text); +/* Assuming TEXT is a filename, find the completion word point for TEXT, + emulating the algorithm readline uses to find the word point. The + filenames that are located by this function assume that filenames + can be quoted, this function should be paired with + filename_maybe_quoted_completer. */ +extern const char *advance_to_filename_maybe_quoted_complete_word_point + (completion_tracker &tracker, const char *text); + extern void noop_completer (struct cmd_list_element *, completion_tracker &tracker, const char *, const char *); From patchwork Tue Aug 20 17:10:42 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 96184 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 7F271387085A for ; Tue, 20 Aug 2024 17:14:04 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id 3F0433870846 for ; Tue, 20 Aug 2024 17:11:06 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 3F0433870846 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 3F0433870846 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724173870; cv=none; b=VNkz5D7NzZyeAkJCQmF5ar2UbvkdOrD4AeTFxxDgufrwneI1aT6reUstw+cwrKvwcSSk09hLaQ5ebwsZ+nvLs06lAfR+Yq8zKjsuHbiQtMeVjF+1nt2cpnAjUmkevquIwprPtZXzZtPy9Tv2tmWMdP/5NfZh1PUMElDV1UHDLro= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724173870; c=relaxed/simple; bh=kRtBKvOJHFDQSmy7LBqTMys4gFbtndSy5zD1JnKxMgM=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=oHZGrv5VelpHqUIQx4f2Y47chNMUEkkS2Qw0FZAUdS7KOu9Mft5ACMuGKL0FR6L5v7nYhe9ZwVvgJNTqXfPk0Iyp9vqBjZ3/+3aoPNNgLRHRg9oH/iTOjLbDdthHn+vNh7a2MMDegDEBCV1trX0PEHFotlV9a1W0TgDw1Lg1kak= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1724173866; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=xpIv8QFtsq6HbcAdqLjxAOhkzqAnNNfRKBtHkbcPtU8=; b=iaDBqIiPNkg9p1ER8fw8kUkna6dyWp4xTR88yACmIT2RVvaLzN86Bc8u55O7BqT8Z6S9VS y/tEEaC3nO5PmfDnm7o7zCIH8BtbIkjjgOvgOryCfW2pp9FAGPdDE/c5e4ghFtNpWjzd62 oJjRcJ+WNMuLfTXn3RuO7akdwTGCcY0= Received: from mail-wr1-f69.google.com (mail-wr1-f69.google.com [209.85.221.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-516-LUdT4nm6NYmiX6uFFw565w-1; Tue, 20 Aug 2024 13:11:04 -0400 X-MC-Unique: LUdT4nm6NYmiX6uFFw565w-1 Received: by mail-wr1-f69.google.com with SMTP id ffacd0b85a97d-371b187634fso1207374f8f.0 for ; Tue, 20 Aug 2024 10:11:04 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1724173863; x=1724778663; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=QkAxQ/KZhJfQ/91IgenzpvSU0B+AkDBnQgU2gzgRoII=; b=Arj+t8qMyC02HxLdTUgdaGvr1jd+oYWC3pKgYwDwz9r0Hb47Rhy4hDYev2y4GgabUc bF9i+WcxeiFpN8p/pa8iChMoDrf1/3X0h8IYE07qyxxBNScdMW6zES2t1CmPjpopfg2G 5RdmnQMe3hWzlcetWBSwuxaFVlTHoME0uM/y7Ne4eOuaqtSJgVx3sA8eNsZZVceZwyjq U1FktBdKrw0kwG/a2ngwxzk4oUh/jKuEb9AaUCJhkOXklkCqH+4csDpAuNvUOfFFKzHb RVDTK3ziROXNpnb9kAFsvbuXezesRt90/oESqpda/w+yOWr94bVe6012Bg1cYpESJhkG O02Q== X-Gm-Message-State: AOJu0YyvbgpBl99xwLfkPC5rtEOgGQ+nUFh64IYdE4a4wC2LPAjYzXpt Sf/tZTNabjdUbqUpXAH8WZ5PJir50qvBvPnFl1wzgotXXG4yJ3U8HELURfliZk5z7nKgcYQoYPG AeFPhyphHwo0COAw6yGphhiAVY4FWRrg8QMT7yVOHskyBGgUgKXFUZILpyrjqBqK5zwfo/rajpm kqUvceCGmUJU9Ae74gNhm3aEE8NZP9cPaPbSWyrg0IJyQ= X-Received: by 2002:a05:6000:4014:b0:371:8319:98de with SMTP id ffacd0b85a97d-371c4aa4599mr2907176f8f.14.1724173862980; Tue, 20 Aug 2024 10:11:02 -0700 (PDT) X-Google-Smtp-Source: AGHT+IEy6AEqTu+VFTS8dF7rbHh/IZ8DZxXWM/KnVZc4lVYKGuRUhNFqFVwjq1E6rfdwWDgQzCU3qQ== X-Received: by 2002:a05:6000:4014:b0:371:8319:98de with SMTP id ffacd0b85a97d-371c4aa4599mr2907137f8f.14.1724173862024; Tue, 20 Aug 2024 10:11:02 -0700 (PDT) Received: from localhost (178.126.90.146.dyn.plus.net. [146.90.126.178]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-371aa7245f9sm9157309f8f.103.2024.08.20.10.11.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 20 Aug 2024 10:11:01 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess , Eli Zaretskii Subject: [PATCHv5 12/14] gdb: add remove-symbol-file command completion Date: Tue, 20 Aug 2024 18:10:42 +0100 Message-Id: <1bda3c025ddb3dff4d670e3f6de1b8b34fed5d40.1724173728.git.aburgess@redhat.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-9.2 required=5.0 tests=BAYES_00, DKIM_INVALID, DKIM_SIGNED, GIT_PATCH_0, KAM_DMARC_NONE, KAM_DMARC_STATUS, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org The 'remove-symbol-file' command doesn't currently offer command completion. This commit addresses this. The 'remove-symbol-file' uses gdb_argv to split its command arguments, this means that the filename the command expects can be quoted. However, the 'remove-symbol-file' command is a little weird in that it also has a '-a' option, if this option is passed then the command expects not a filename, but an address. Currently the remove_symbol_file_command function splits the command args using gdb_argv, checks for a '-a' flag by looking at the first argument value, and then expects the filename or address to occupy a single entry in the gdb_argv array. The first thing I do is handle the '-a' flag using GDB's option system. I model this option as a flag_option_def (a boolean option). I've dropped the use of gdb_argv and instead use the new(ish) function extract_single_filename_arg, which was added a couple of commits back, to parse the filename argument (when '-a' is not given). If '-a' is given the the remove-symbol-file command expects an address rather than a filename. As we previously split the arguments using gdb_argv this meant the address needed to appear as a single argument. So a user could write: (gdb) remove-symbol-file 0x1234 Or they could write: (gdb) remove-symbol-file some_function Both of these would work fine. But a user could not write: (gdb) remove-symbol-file some_function + 0x1000 As only the 'some_function' part would be processed. Now the user could do this: (gdb) remove-symbol-file "some_function + 0x1000" By enclosing the address expression in quotes this would be handled as a single argument. However, this is a little weird, that's not how commands like 'print' or 'x' work. Also this functionality was neither documented, or tested. And so, in this commit, by removing the use of gdb_argv I bring the 'remove-symbol-file' command inline with GDB's other commands that take an expression, the quotes are no longer needed. Usually in a completer we call 'complete_options', but don't actually capture the option values. But for remove-symbol-file I do. This allows me to spot when the '-a' option has been given, I can then complete the rest of the command line as either a filename or an expression. Reviewed-By: Eli Zaretskii Reviewed-By: Eli Zaretskii --- gdb/NEWS | 10 + gdb/doc/gdb.texinfo | 1 + gdb/symfile.c | 114 ++++++-- .../gdb.base/filename-completion.exp | 3 +- gdb/testsuite/gdb.base/sym-file.exp | 258 ++++++++++-------- 5 files changed, 238 insertions(+), 148 deletions(-) diff --git a/gdb/NEWS b/gdb/NEWS index 81aa8af2338..6161d40bcff 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -35,6 +35,16 @@ * Remove support (native and remote) for QNX Neutrino (triplet `i[3456]86-*-nto*`). +* Changed commands + +remove-symbol-file + This command now supports file-name completion. + +remove-symbol-file -a ADDRESS + The ADDRESS expression can now be a full expression consisting of + multiple terms, e.g. 'function + 0x1000' (without quotes), + previously only a single term could be given. + *** Changes in GDB 15 * The MPX commands "show/set mpx bound" have been deprecated, as Intel diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 7938b0799f9..e7f862e80f8 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -21892,6 +21892,7 @@ (@value{GDBP}) @end smallexample +The @var{address} can be any expression which evaluates to an address. @code{remove-symbol-file} does not repeat if you press @key{RET} after using it. diff --git a/gdb/symfile.c b/gdb/symfile.c index 5054d101cd5..2292ecaf344 100644 --- a/gdb/symfile.c +++ b/gdb/symfile.c @@ -2330,39 +2330,90 @@ add_symbol_file_command (const char *args, int from_tty) } +/* Option support for 'remove-symbol-file' command. */ + +struct remove_symbol_file_options +{ + /* True when the '-a' flag was passed. */ + bool address_flag = false; +}; + +using remove_symbol_file_options_opt_def + = gdb::option::flag_option_def; + +static const gdb::option::option_def remove_symbol_file_opt_defs[] = { + remove_symbol_file_options_opt_def { + "a", + [] (remove_symbol_file_options *opt) { return &opt->address_flag; }, + N_("Select a symbol file containing ADDRESS.") + }, +}; + +static inline gdb::option::option_def_group +make_remove_symbol_file_def_group (remove_symbol_file_options *opts) +{ + return {{remove_symbol_file_opt_defs}, opts}; +} + +/* Completion function for 'remove-symbol-file' command. */ + +static void +remove_symbol_file_command_completer (struct cmd_list_element *ignore, + completion_tracker &tracker, + const char *text, const char * /* word */) +{ + /* Unlike many command completion functions we do gather the option + values here. How we complete the rest of the command depends on + whether the '-a' flag has been given or not. */ + remove_symbol_file_options opts; + auto grp = make_remove_symbol_file_def_group (&opts); + if (gdb::option::complete_options + (tracker, &text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR, grp)) + return; + + /* Complete the rest of the command line as either a filename or an + expression (which will evaluate to an address) if the '-a' flag was + given. */ + if (!opts.address_flag) + { + const char *word + = advance_to_filename_maybe_quoted_complete_word_point (tracker, text); + filename_maybe_quoted_completer (ignore, tracker, text, word); + } + else + { + const char *word + = advance_to_expression_complete_word_point (tracker, text); + symbol_completer (ignore, tracker, text, word); + } +} + /* This function removes a symbol file that was added via add-symbol-file. */ static void remove_symbol_file_command (const char *args, int from_tty) { - struct objfile *objf = NULL; - struct program_space *pspace = current_program_space; - dont_repeat (); - if (args == NULL) - error (_("remove-symbol-file: no symbol file provided")); + remove_symbol_file_options opts; + auto grp = make_remove_symbol_file_def_group (&opts); + gdb::option::process_options + (&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR, grp); - gdb_argv argv (args); + struct objfile *objf = nullptr; - if (strcmp (argv[0], "-a") == 0) + if (opts.address_flag) { - /* Interpret the next argument as an address. */ - CORE_ADDR addr; + if (args == nullptr || *args == '\0') + error (_("remove-symbol-file: no address provided")); - if (argv[1] == NULL) - error (_("Missing address argument")); - - if (argv[2] != NULL) - error (_("Junk after %s"), argv[1]); - - addr = parse_and_eval_address (argv[1]); + CORE_ADDR addr = parse_and_eval_address (args); for (objfile *objfile : current_program_space->objfiles ()) { if ((objfile->flags & OBJF_USERLOADED) != 0 && (objfile->flags & OBJF_SHARED) != 0 - && objfile->pspace () == pspace + && objfile->pspace () == current_program_space && is_addr_in_objfile (addr, objfile)) { objf = objfile; @@ -2370,21 +2421,18 @@ remove_symbol_file_command (const char *args, int from_tty) } } } - else if (argv[0] != NULL) + else { - /* Interpret the current argument as a file name. */ - - if (argv[1] != NULL) - error (_("Junk after %s"), argv[0]); - - gdb::unique_xmalloc_ptr filename (tilde_expand (argv[0])); + std::string filename = extract_single_filename_arg (args); + if (filename.empty ()) + error (_("remove-symbol-file: no symbol file provided")); for (objfile *objfile : current_program_space->objfiles ()) { if ((objfile->flags & OBJF_USERLOADED) != 0 && (objfile->flags & OBJF_SHARED) != 0 - && objfile->pspace () == pspace - && filename_cmp (filename.get (), objfile_name (objfile)) == 0) + && objfile->pspace () == current_program_space + && filename_cmp (filename.c_str (), objfile_name (objfile)) == 0) { objf = objfile; break; @@ -3830,14 +3878,22 @@ READNOW_READNEVER_HELP), &cmdlist); set_cmd_completer (c, filename_maybe_quoted_completer); - c = add_cmd ("remove-symbol-file", class_files, - remove_symbol_file_command, _("\ + const auto remove_symbol_file_opts + = make_remove_symbol_file_def_group (nullptr); + static std::string remove_symbol_file_cmd_help + = gdb::option::build_help (_("\ Remove a symbol file added via the add-symbol-file command.\n\ Usage: remove-symbol-file FILENAME\n\ remove-symbol-file -a ADDRESS\n\ The file to remove can be identified by its filename or by an address\n\ -that lies within the boundaries of this symbol file in memory."), +that lies within the boundaries of this symbol file in memory.\n\ +Options:\n\ +%OPTIONS%"), remove_symbol_file_opts); + c = add_cmd ("remove-symbol-file", class_files, + remove_symbol_file_command, + remove_symbol_file_cmd_help.c_str (), &cmdlist); + set_cmd_completer_handle_brkchars (c, remove_symbol_file_command_completer); c = add_cmd ("load", class_files, load_command, _("\ Dynamically load FILE into the running program.\n\ diff --git a/gdb/testsuite/gdb.base/filename-completion.exp b/gdb/testsuite/gdb.base/filename-completion.exp index cf00d007ca7..62fb49570a6 100644 --- a/gdb/testsuite/gdb.base/filename-completion.exp +++ b/gdb/testsuite/gdb.base/filename-completion.exp @@ -122,7 +122,8 @@ proc test_gdb_complete_filename_multiple { proc run_quoting_and_escaping_tests { root } { # Test all the commands which allow quoting of filenames, and # which require whitespace to be escaped in unquoted filenames. - foreach_with_prefix cmd { file exec-file symbol-file add-symbol-file } { + foreach_with_prefix cmd { file exec-file symbol-file add-symbol-file \ + remove-symbol-file } { gdb_start # Completing 'thread apply all ...' commands uses a custom word diff --git a/gdb/testsuite/gdb.base/sym-file.exp b/gdb/testsuite/gdb.base/sym-file.exp index 3e36e65d1c5..17650cbce3a 100644 --- a/gdb/testsuite/gdb.base/sym-file.exp +++ b/gdb/testsuite/gdb.base/sym-file.exp @@ -67,134 +67,156 @@ if {[prepare_for_testing "failed to prepare" $binfile "$srcfile $srcfile2" $exe gdb_load_shlib ${lib_so} -if {![runto_main]} { - return -} - -# 1) Run to gdb_add_symbol_file in $srcfile for adding the library's -# symbols. -gdb_breakpoint gdb_add_symbol_file -gdb_continue_to_breakpoint gdb_add_symbol_file - -# 2) Set a pending breakpoint at bar in $srcfile3. -set result [gdb_breakpoint bar allow-pending] -if {!$result} { - return -} - -# 3) Add the library's symbols using 'add-symbol-file'. -set result [gdb_test "add-symbol-file ${lib_syms} addr" \ - "Reading symbols from .*${lib_syms}\\.\\.\\." \ - "add-symbol-file ${lib_basename}.so addr" \ - "add symbol table from file \".*${lib_basename}\\.so\"\ - at.*\\(y or n\\) " \ - "y"] -if {$result != 0} { - return -} - -# 4) 'info files' must display $srcfile3. -gdb_test "info files" \ - "^(?=(.*${lib_basename})).*" \ - "info files must display ${lib_basename}" - -# 5) Continue to bar in $srcfile3 to ensure that the breakpoint -# was bound correctly after adding $shilb_name. -set lnum_bar [gdb_get_line_number "break at bar" $srcfile3] -gdb_continue_to_breakpoint bar ".*${lib_basename}\\.c:$lnum_bar.*" - -# 6) Set a breakpoint at foo in $srcfile3. -set result [gdb_breakpoint foo] -if {!$result} { - return -} - -# 7) Continue to foo in $srcfile3 to ensure that the breakpoint -# was bound correctly. -set lnum_foo [gdb_get_line_number "break at foo" $srcfile3] -gdb_continue_to_breakpoint foo ".*${lib_basename}\\.c:$lnum_foo.*" - -# 8) Set a breakpoint at gdb_remove_symbol_file in $srcfile for -# removing the library's symbols. -set result [gdb_breakpoint gdb_remove_symbol_file] -if {!$result} { - return -} +proc do_test { remove_expr } { + global lib_basename lib_syms srcfile srcfile3 -# 9) Continue to gdb_remove_symbol_file in $srcfile. -gdb_continue_to_breakpoint gdb_remove_symbol_file - -# 10) Remove the library's symbols using 'remove-symbol-file'. -set result [gdb_test "remove-symbol-file -a addr" \ - ""\ - "remove-symbol-file -a addr" \ - "Remove symbol table from file \".*${lib_basename}\\.so\"\\?\ -.*\\(y or n\\) " \ - "y"] -if {$result != 0} { - return -} + clean_restart $::binfile -# 11) 'info files' must not display ${lib_basename}, anymore. -gdb_test "info files" \ - "^(?!(.*${lib_basename})).*" \ - "info files must not display ${lib_basename}" + if {![runto_main]} { + return + } -# 12) Check that the breakpoints at foo and bar are pending after -# removing the library's symbols. -gdb_test "info breakpoints 3" \ - ".*PENDING.*" \ - "breakpoint at foo is pending" - -gdb_test "info breakpoints 4" \ - ".*PENDING.*" \ - "breakpoint at bar is pending" - -# 13) Check that the execution can continue without error. -set lnum_reload [gdb_get_line_number "reload lib here"] -gdb_breakpoint $lnum_reload -gdb_continue_to_breakpoint reload ".*${srcfile}:$lnum_reload.*" - -# 14) Regression test for a stale breakpoints bug. Check whether -# unloading symbols manually without the program actually unloading -# the library, when breakpoints are inserted doesn't leave stale -# breakpoints behind. -with_test_prefix "stale bkpts" { - # Force breakpoints always inserted. - gdb_test_no_output "set breakpoint always-inserted on" - - # Get past the library reload. + # 1) Run to gdb_add_symbol_file in $srcfile for adding the library's + # symbols. + gdb_breakpoint gdb_add_symbol_file gdb_continue_to_breakpoint gdb_add_symbol_file - # Load the library's symbols. - gdb_test "add-symbol-file ${lib_syms} addr" \ - "Reading symbols from .*${lib_syms}\\.\\.\\." \ - "add-symbol-file ${lib_basename}.so addr" \ - "add symbol table from file \".*${lib_syms}\"\ + # 2) Set a pending breakpoint at bar in $srcfile3. + set result [gdb_breakpoint bar allow-pending] + if {!$result} { + return + } + + # 3) Add the library's symbols using 'add-symbol-file'. + set result [gdb_test "add-symbol-file ${lib_syms} addr" \ + "Reading symbols from .*${lib_syms}\\.\\.\\." \ + "add-symbol-file ${lib_basename}.so addr" \ + "add symbol table from file \".*${lib_basename}\\.so\"\ + at.*\\(y or n\\) " \ + "y"] + if {$result != 0} { + return + } + + # 4) 'info files' must display $srcfile3. + gdb_test "info files" \ + "^(?=(.*${lib_basename})).*" \ + "info files must display ${lib_basename}" + + # 5) Continue to bar in $srcfile3 to ensure that the breakpoint + # was bound correctly after adding $shilb_name. + set lnum_bar [gdb_get_line_number "break at bar" $srcfile3] + gdb_continue_to_breakpoint bar ".*${lib_basename}\\.c:$lnum_bar.*" + + # 6) Set a breakpoint at foo in $srcfile3. + set result [gdb_breakpoint foo] + if {!$result} { + return + } + + # 7) Continue to foo in $srcfile3 to ensure that the breakpoint + # was bound correctly. + set lnum_foo [gdb_get_line_number "break at foo" $srcfile3] + gdb_continue_to_breakpoint foo ".*${lib_basename}\\.c:$lnum_foo.*" + + # 8) Set a breakpoint at gdb_remove_symbol_file in $srcfile for + # removing the library's symbols. + set result [gdb_breakpoint gdb_remove_symbol_file] + if {!$result} { + return + } + + # 9) Continue to gdb_remove_symbol_file in $srcfile. + gdb_continue_to_breakpoint gdb_remove_symbol_file + + # 10) Remove the library's symbols using 'remove-symbol-file'. + set result [gdb_test "remove-symbol-file ${remove_expr}" \ + ""\ + "remove-symbol-file" \ + "Remove symbol table from file \".*${lib_basename}\\.so\"\\?\ +.*\\(y or n\\) " \ + "y"] + if {$result != 0} { + return + } + + # 11) 'info files' must not display ${lib_basename}, anymore. + gdb_test "info files" \ + "^(?!(.*${lib_basename})).*" \ + "info files must not display ${lib_basename}" + + # 12) Check that the breakpoints at foo and bar are pending after + # removing the library's symbols. + gdb_test "info breakpoints 3" \ + ".*PENDING.*" \ + "breakpoint at foo is pending" + + gdb_test "info breakpoints 4" \ + ".*PENDING.*" \ + "breakpoint at bar is pending" + + # 13) Check that the execution can continue without error. + set lnum_reload [gdb_get_line_number "reload lib here"] + gdb_breakpoint $lnum_reload + gdb_continue_to_breakpoint reload ".*${srcfile}:$lnum_reload.*" + + # 14) Regression test for a stale breakpoints bug. Check whether + # unloading symbols manually without the program actually unloading + # the library, when breakpoints are inserted doesn't leave stale + # breakpoints behind. + with_test_prefix "stale bkpts" { + # Force breakpoints always inserted. + gdb_test_no_output "set breakpoint always-inserted on" + + # Get past the library reload. + gdb_continue_to_breakpoint gdb_add_symbol_file + + # Load the library's symbols. + gdb_test "add-symbol-file ${lib_syms} addr" \ + "Reading symbols from .*${lib_syms}\\.\\.\\." \ + "add-symbol-file ${lib_basename}.so addr" \ + "add symbol table from file \".*${lib_syms}\"\ at.*\\(y or n\\) " \ - "y" + "y" - # Set a breakpoint at baz, in the library. - gdb_breakpoint baz + # Set a breakpoint at baz, in the library. + gdb_breakpoint baz - gdb_test "info breakpoints 7" ".*y.*0x.*in baz.*" \ - "breakpoint at baz is resolved" + gdb_test "info breakpoints 7" ".*y.*0x.*in baz.*" \ + "breakpoint at baz is resolved" - # Unload symbols manually without the program actually unloading - # the library. - gdb_test "remove-symbol-file -a addr" \ - "" \ - "remove-symbol-file -a addr" \ - "Remove symbol table from file \".*${lib_basename}\\.so\"\\?\ + # Unload symbols manually without the program actually unloading + # the library. + gdb_test "remove-symbol-file ${remove_expr}" \ + "" \ + "remove-symbol-file" \ + "Remove symbol table from file \".*${lib_basename}\\.so\"\\?\ .*\\(y or n\\) " \ - "y" + "y" + + gdb_test "info breakpoints 7" ".*PENDING.*" \ + "breakpoint at baz is pending" - gdb_test "info breakpoints 7" ".*PENDING.*" \ - "breakpoint at baz is pending" + # Check that execution can continue without error. If GDB leaves + # breakpoints behind, we'll get back a spurious SIGTRAP. + set lnum_end [gdb_get_line_number "end here"] + gdb_breakpoint $lnum_end + gdb_continue_to_breakpoint "end here" ".*end here.*" + } +} - # Check that execution can continue without error. If GDB leaves - # breakpoints behind, we'll get back a spurious SIGTRAP. - set lnum_end [gdb_get_line_number "end here"] - gdb_breakpoint $lnum_end - gdb_continue_to_breakpoint "end here" ".*end here.*" +foreach remove_expr [list addr bar "bar + 0x10" "${lib_syms}" ] { + # Don't use full filenames in the test prefix. Also, add '-a' to + # all the REMOVE_EXPR values which are addresses rather than + # filenames. + set prefix $remove_expr + if { $prefix == $lib_syms } { + set prefix [file tail $prefix] + } else { + set remove_expr "-a $remove_expr" + } + + with_test_prefix "remove_expr=$prefix" { + do_test $remove_expr + } } From patchwork Tue Aug 20 17:10:43 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 96186 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 6FAD8384188C for ; Tue, 20 Aug 2024 17:14:38 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id 9801D386F43A for ; Tue, 20 Aug 2024 17:11:07 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 9801D386F43A Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 9801D386F43A Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724173870; cv=none; b=qK60ttWZKBz6S+ghHXKOGXxUR+P2ewtxda65HUOJl5MSVI1Lh8W3ALQoVyfFJg2qIVV+VGouJJHouKjyxP+AQUlPwhSJ/OQMLtMGQFIa9WnLAvCeklgFoCSQLjKHRskPRor8a5I88D6djW2jEBftPd5hWa9BhQOyUwsGRasalYo= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724173870; c=relaxed/simple; bh=GNIayhkkHjJsCMAjhF/wvDneGtfF7PecwCWvd4nD5Ew=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=I9r5XIEKmNonLStM46EOusR8dkXxK2tqcAMfVbJ3cYm7Iqz9/6IVtHKVNdcWRHcJi9oGsz7JlhlqoUDLHXrj8Nhn0CmjzDFH/12iU74J6m0OzOK5JcJ3LLcM2biYGhCAtYbs0Cg1sDzZqa662oSZwVt5aKBP9TzeG5PE9Xi57To= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1724173867; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=/ud0+6q8LhbKheLGnZOm0r7htxKg1F3N0rBfHYhjUDE=; b=MLvi5NgkY+rX4qJK/t8fAV45rDEz7IfuLtwXtV2sfKXOUkeBsL1W+iwWv29bZPSWCgmEuG 57HiDhXPBWRjwjbw1OhMvBXmbP8iSF6gMCUoOEBgM3HVe5NSCVquvExLRI+d8/weufmH9+ /IQyqMo+nU1HIQCyMA/7Yz8js15eJts= Received: from mail-wr1-f70.google.com (mail-wr1-f70.google.com [209.85.221.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-689-RMuPZxWoOVyB0qN0LC1Ncw-1; Tue, 20 Aug 2024 13:11:06 -0400 X-MC-Unique: RMuPZxWoOVyB0qN0LC1Ncw-1 Received: by mail-wr1-f70.google.com with SMTP id ffacd0b85a97d-3719ce5627eso2408275f8f.1 for ; Tue, 20 Aug 2024 10:11:06 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1724173865; x=1724778665; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=/ud0+6q8LhbKheLGnZOm0r7htxKg1F3N0rBfHYhjUDE=; b=cOattwzgP2UEpPwOABXrRFAOWcQ54XA5Qi/i+ObotjMRcJDQxNximA+IxcwRGGXsDm NwD6UkQOUgINOPnYkUBNt3XtV2FO+nCFqvzxtM299UbvkPWe+Kr3OwSss0U1eBqdrgG8 UJIkEjN37MTjgNRRUMagfp9ebIc/hOrXZdFDnxM70C42TylD8RSLQfoaDB48LknlEl1f lDsbgofxh/Z8oel+CRQ7Z9wTIPU9KYCZLbFh7T9t7oZkXxUV2snXMY5c72HX9dF6rECS NgqGsbjncZU330GOLTNn8xyOFn+44ZU1vVe0svmgQiwkVLRtyNbVbLNKNR1yku6spOCK 7jbg== X-Gm-Message-State: AOJu0YxOT8xvVEHEThiOX2vcnSB07+hqqg9k+EWhfjxfgnFiWjQjoGGD pZO+uDZpx4nd9nfC3MRhC0zuX+/2wfF+levX7+9w9CpNZAEjyledtAhaj8QbI4h0Nb/cOK4C7Ze ZB1N45UoAATcKKcUEn1N1uSyaILRmbBYhT6OOoobBhH4FB1mG+FS7b5YDrcMSO9Eo6jexnslg8O MbO7dD0fOdv4SnDF4BRSgAhT9jrzw/gLgxad/gTzGS32Y= X-Received: by 2002:a5d:654e:0:b0:371:8eb3:8c64 with SMTP id ffacd0b85a97d-371946a5d52mr12349830f8f.54.1724173864587; Tue, 20 Aug 2024 10:11:04 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGekw03rR2fQFJowqqnHT+XFBnnAKmazXtsim22PvOcH5D/Kyfhlo1KcGd5Eczg4HDQc60J4Q== X-Received: by 2002:a5d:654e:0:b0:371:8eb3:8c64 with SMTP id ffacd0b85a97d-371946a5d52mr12349792f8f.54.1724173863608; Tue, 20 Aug 2024 10:11:03 -0700 (PDT) Received: from localhost (178.126.90.146.dyn.plus.net. [146.90.126.178]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-429ded28cdasm199526755e9.16.2024.08.20.10.11.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 20 Aug 2024 10:11:02 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess , Eli Zaretskii Subject: [PATCHv5 13/14] gdb: allow quoted filenames for commands that have custom completion Date: Tue, 20 Aug 2024 18:10:43 +0100 Message-Id: <82288d6aab448ec71e2902e48ab8d2b057d415a3.1724173728.git.aburgess@redhat.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-10.4 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org This commit changes how GDB processes command arguments for the following commands: compile file maint print c-tdesc save gdb-index After this commit these commands will now expect their single filename argument to be (optionally) quoted if it contains any special characters (e.g. whit space or quotes). If the filename does not contain any special characters then nothing changes. As an example: (gdb) save gdb-index /path/to/some/directory/ will work before and after this patch. However, if the directory name contains a white space then before this patch a user would write: (gdb) save gdb-index /path/to some/directory/ But this will now fail as GDB will consider this as two arguments, '/path/to' and 'some/directory/'. To pass this single directory name a user must now do one of these: (gdb) save gdb-index "/path/to some/directory/" (gdb) save gdb-index '/path/to some/directory/' (gdb) save gdb-index /path/to\ some/directory/ This brings these commands into line with commands like 'file' and 'symbol-file', which have supported quoted filenames for a while. The motivation for this change is to make handling of filename arguments consistent throughout GDB. We can't move to all commands taking non-quoted filenames as the non-quoted style only allows for a single argument. Additionally, the non-quoted style doesn't allow for filenames that end in white space (though this is probably pretty rare). So, if we want to have consistency the only choice is to move towards supporting quote filenames. Reviewed-By: Eli Zaretskii Reviewed-By: Eli Zaretskii --- gdb/NEWS | 7 +++++ gdb/compile/compile.c | 11 ++++---- gdb/doc/gdb.texinfo | 9 +++++++ gdb/dwarf2/index-write.c | 8 +++--- gdb/target-descriptions.c | 27 +++++++++---------- .../gdb.base/filename-completion.exp | 7 +++-- gdb/testsuite/gdb.compile/compile.exp | 2 +- 7 files changed, 44 insertions(+), 27 deletions(-) diff --git a/gdb/NEWS b/gdb/NEWS index 6161d40bcff..ee453ed376d 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -45,6 +45,13 @@ remove-symbol-file -a ADDRESS multiple terms, e.g. 'function + 0x1000' (without quotes), previously only a single term could be given. +compile file +maint print c-tdesc +save gdb-index + These commands now require their filename argument to be quoted if + it contains white space or quote characters. If the argument + contains no such special characters then quoting is not required. + *** Changes in GDB 15 * The MPX commands "show/set mpx bound" have been deprecated, as Intel diff --git a/gdb/compile/compile.c b/gdb/compile/compile.c index 6c5f33e0c19..89f979000ba 100644 --- a/gdb/compile/compile.c +++ b/gdb/compile/compile.c @@ -303,14 +303,13 @@ compile_file_command (const char *args, int from_tty) enum compile_i_scope_types scope = options.raw ? COMPILE_I_RAW_SCOPE : COMPILE_I_SIMPLE_SCOPE; - args = skip_spaces (args); + std::string filename = extract_single_filename_arg (args); /* After processing options, check whether we have a filename. */ - if (args == nullptr || args[0] == '\0') + if (filename.empty ()) error (_("You must provide a filename for this command.")); - args = skip_spaces (args); - std::string abspath = gdb_abspath (args); + std::string abspath = gdb_abspath (filename.c_str ()); std::string buffer = string_printf ("#include \"%s\"\n", abspath.c_str ()); eval_compile_command (NULL, buffer.c_str (), scope, NULL); } @@ -328,8 +327,8 @@ compile_file_command_completer (struct cmd_list_element *ignore, (tracker, &text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR, group)) return; - word = advance_to_deprecated_filename_complete_word_point (tracker, text); - deprecated_filename_completer (ignore, tracker, text, word); + word = advance_to_filename_maybe_quoted_complete_word_point (tracker, text); + filename_maybe_quoted_completer (ignore, tracker, text, word); } /* Handle the input from the 'compile code' command. The diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index e7f862e80f8..f158d3dafb1 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -21344,6 +21344,9 @@ @smallexample compile file /home/user/example.c @end smallexample + +The @var{filename} argument supports escaping and quoting, see +@ref{Filename Arguments,,Filenames As Command Arguments}. @end table @table @code @@ -22790,6 +22793,9 @@ @file{@var{symbol-file}.debug_names} and @file{@var{symbol-file}.debug_str}. The files are created in the given @var{directory}. + +The @var{directory} argument supports escaping and quoting, see +@ref{Filename Arguments,,Filenames As Command Arguments}. @end table Once you have created an index file you can merge it into your symbol @@ -41791,6 +41797,9 @@ @var{file}) must only contain a single feature. The source file produced is different in this case. +The @var{file} argument supports escaping and quoting, see +@ref{Filename Arguments,,Filenames As Command Arguments}. + @kindex maint print xml-tdesc @item maint print xml-tdesc @r{[}@var{file}@r{]} Print the target description (@pxref{Target Descriptions}) as an XML diff --git a/gdb/dwarf2/index-write.c b/gdb/dwarf2/index-write.c index ccbaea73380..2633a69df3b 100644 --- a/gdb/dwarf2/index-write.c +++ b/gdb/dwarf2/index-write.c @@ -1621,8 +1621,8 @@ gdb_save_index_cmd_completer (struct cmd_list_element *ignore, (tracker, &text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, grp)) return; - word = advance_to_deprecated_filename_complete_word_point (tracker, text); - deprecated_filename_completer (ignore, tracker, text, word); + word = advance_to_filename_maybe_quoted_complete_word_point (tracker, text); + filename_maybe_quoted_completer (ignore, tracker, text, word); } /* Implementation of the `save gdb-index' command. @@ -1639,10 +1639,10 @@ save_gdb_index_command (const char *args, int from_tty) gdb::option::process_options (&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, group); - if (args == nullptr || *args == '\0') + std::string directory = extract_single_filename_arg (args); + if (directory.empty ()) error (_("usage: save gdb-index [-dwarf-5] DIRECTORY")); - std::string directory (gdb_tilde_expand (args)); dw_index_kind index_kind = (opts.dwarf_5 ? dw_index_kind::DEBUG_NAMES : dw_index_kind::GDB_INDEX); diff --git a/gdb/target-descriptions.c b/gdb/target-descriptions.c index d3ee4e9f8ca..d78da14918f 100644 --- a/gdb/target-descriptions.c +++ b/gdb/target-descriptions.c @@ -1691,14 +1691,15 @@ static void maint_print_c_tdesc_cmd (const char *args, int from_tty) { const struct target_desc *tdesc; - const char *filename; maint_print_c_tdesc_options opts; auto grp = make_maint_print_c_tdesc_options_def_group (&opts); gdb::option::process_options (&args, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR, grp); - if (args == NULL) + std::string filename = extract_single_filename_arg (args); + + if (filename.empty ()) { /* Use the global target-supplied description, not the current architecture's. This lets a GDB for one architecture generate C @@ -1706,26 +1707,24 @@ maint_print_c_tdesc_cmd (const char *args, int from_tty) initialization code will reject the new description. */ target_desc_info *tdesc_info = ¤t_inferior ()->tdesc_info; tdesc = tdesc_info->tdesc; - filename = tdesc_info->filename.data (); + if (tdesc_info->filename.data () != nullptr) + filename = std::string (tdesc_info->filename.data ()); } else { /* Use the target description from the XML file. */ - filename = args; - tdesc = file_read_description_xml (filename); + tdesc = file_read_description_xml (filename.c_str ()); } if (tdesc == NULL) error (_("There is no target description to print.")); - if (filename == NULL) + if (filename.empty ()) filename = "fetched from target"; - std::string filename_after_features (filename); - auto loc = filename_after_features.rfind ("/features/"); - + auto loc = filename.rfind ("/features/"); if (loc != std::string::npos) - filename_after_features = filename_after_features.substr (loc + 10); + filename = filename.substr (loc + 10); /* Print c files for target features instead of target descriptions, because c files got from target features are more flexible than the @@ -1736,13 +1735,13 @@ maint_print_c_tdesc_cmd (const char *args, int from_tty) error (_("only target descriptions with 1 feature can be used " "with -single-feature option")); - print_c_feature v (filename_after_features); + print_c_feature v (filename); tdesc->accept (v); } else { - print_c_tdesc v (filename_after_features); + print_c_tdesc v (filename); tdesc->accept (v); } @@ -1760,8 +1759,8 @@ maint_print_c_tdesc_cmd_completer (struct cmd_list_element *ignore, (tracker, &text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_ERROR, grp)) return; - word = advance_to_deprecated_filename_complete_word_point (tracker, text); - deprecated_filename_completer (ignore, tracker, text, word); + word = advance_to_filename_maybe_quoted_complete_word_point (tracker, text); + filename_maybe_quoted_completer (ignore, tracker, text, word); } /* Implement the maintenance print xml-tdesc command. */ diff --git a/gdb/testsuite/gdb.base/filename-completion.exp b/gdb/testsuite/gdb.base/filename-completion.exp index 62fb49570a6..7ba055b9ae7 100644 --- a/gdb/testsuite/gdb.base/filename-completion.exp +++ b/gdb/testsuite/gdb.base/filename-completion.exp @@ -123,7 +123,10 @@ proc run_quoting_and_escaping_tests { root } { # Test all the commands which allow quoting of filenames, and # which require whitespace to be escaped in unquoted filenames. foreach_with_prefix cmd { file exec-file symbol-file add-symbol-file \ - remove-symbol-file } { + remove-symbol-file \ + "target core" "target exec" "target tfile" \ + "maint print c-tdesc" "compile file" \ + "save gdb-index" "save gdb-index -dwarf-5" } { gdb_start # Completing 'thread apply all ...' commands uses a custom word @@ -298,7 +301,7 @@ proc run_unquoted_tests_core { root cmd { prefix "" } } { proc run_unquoted_tests { root } { # Test all the commands which allow quoting of filenames, and # which require whitespace to be escaped in unquoted filenames. - foreach_with_prefix cmd { "maint print c-tdesc" "set logging file" \ + foreach_with_prefix cmd { "set logging file" \ "target core" "add-auto-load-safe-path" } { run_unquoted_tests_core $root $cmd } diff --git a/gdb/testsuite/gdb.compile/compile.exp b/gdb/testsuite/gdb.compile/compile.exp index cd596335859..2c2e3217b19 100644 --- a/gdb/testsuite/gdb.compile/compile.exp +++ b/gdb/testsuite/gdb.compile/compile.exp @@ -66,7 +66,7 @@ if {[skip_compile_feature_untested]} { gdb_test_no_output "compile -- f = 10" \ "test abbreviations and code delimiter" -gdb_test "compile f = 10;" ".*= 10;: No such file.*" \ +gdb_test "compile f = 10;" "^Junk after filename \"=\": 10;" \ "Test abbreviations and code collision" gdb_test_no_output "compile -r -- void _gdb_expr(){int i = 5;}" \ From patchwork Tue Aug 20 17:10:44 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 96187 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 369923842FEC for ; Tue, 20 Aug 2024 17:14:57 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id E47B3384477A for ; Tue, 20 Aug 2024 17:11:08 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org E47B3384477A Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org E47B3384477A Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724173872; cv=none; b=lbPgwnaq4Zv7rCwFsOKIniC3TNvt5oZonCqaXZZnLPjrcyAkUUFVFvzhZjNQZ6sSTXAXvTqRNHOv0flaQ1cy2Zoh9L4B1w2TKoQCUvR6gd+K/Hw7W5iCtpE0QF4L2fztDkAGo2HF9MjDbgMiqJPydPLVgRntcotHwUXaSQ93V6U= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1724173872; c=relaxed/simple; bh=5lBDTBP8W6xCbXlZT9l4jV1r6B/0aHEWz38F4oebTEI=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=VyVpJcJeilhQp2QW2cZGXIRYdky4VtnriDZ98dS1Vl2lVy1YdOZSjXmKBq2qR8Fnaf3eO6rnN8YCf/mZX0vBQwEYLxVykfjygU8QBOsbiwjIcRtgnlS1viEBnSpmHCeZz7Ho2hVAlBUzU/ikBveSN2JXoDNCwgYFowaQ7iTmUP8= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1724173868; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=HyMg2MYl5j4zJneVO9LPRkKazyiOAQswH4hg5sshgaI=; b=CQe/boRpQc3Rmkg8/ZqzTOsz6JDbVcVYJnlOB9d04PSkowTL7I4y+79OQRXPAvOB+YtILu 5zLDu0hT7+rHDjvkGRnVGHzLooS8X+SdL/izzJtSvUTDDjYKGpo5MzIheGB9Tj+ORQpM10 QsGkoUI9hdRLhYH57PPxk387ro9NRzo= Received: from mail-wm1-f69.google.com (mail-wm1-f69.google.com [209.85.128.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-19-Zemykjh8PfiAAvrwqXScvQ-1; Tue, 20 Aug 2024 13:11:07 -0400 X-MC-Unique: Zemykjh8PfiAAvrwqXScvQ-1 Received: by mail-wm1-f69.google.com with SMTP id 5b1f17b1804b1-42808685ef0so50350035e9.2 for ; Tue, 20 Aug 2024 10:11:06 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1724173866; x=1724778666; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=HyMg2MYl5j4zJneVO9LPRkKazyiOAQswH4hg5sshgaI=; b=kM6BFQSVBLpSveHKX7Ne1SbZeKkhXKyhRWOzI18prvH0uzfO0YJMMNhg2jNLJNJkr7 uJt1VxVzTaVNg4CbRVOK3kzbox4efOMUzE6Zet7Se+NJmU8OQpONC+Nx3Ydsh4j9JmCT gIG/ReaodymjKNh17mDx91Awb/uKJnakKI2RQNceRDHA9pkPgVv707J49RyAdfbCsoZs 4Oy5SgsPBkqF+2onKRUb4gfacfBephvqfG+gY4HZboiku/4crWOWRF537bf6DNamf1qZ 11xDyuc8P84R/WUVPXUB6BG0uhnLXTGUZ+stvm4YdB0xvUpUvwaWwfLnzqxwdSrHk8re 4s+g== X-Gm-Message-State: AOJu0YyHRqrBcFnTETvlIv6LFMvOQLtnjDWTRkzxJFbR0aeA9r8miQsJ XvMM++r8jsLt2EBzI8jQeE2qkx6iFWBqHOoTR/QbueOBrJyHUTxTTCyeKSOhdQhEnIGhBzt6KrR DrOODl6GR2UYgG1JupqTqXor7ZA7cTpa4ghQ7mYne52zD9ftsOi9D5nmdpMfLI57tl92CW3aEFq 5M342hFNOqDokwLfzjrTXOLf7v2bLs+HuFhz8SLlAcFgc= X-Received: by 2002:a05:600c:5845:b0:427:abed:3602 with SMTP id 5b1f17b1804b1-42abd2457a0mr296135e9.24.1724173865399; Tue, 20 Aug 2024 10:11:05 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGlpcPfyDWMpaSzqa1d9PL8qf/uPWjPDUFiYpOJ3s3MungIe6UHd933S1FycsIPiwP1UOENKw== X-Received: by 2002:a05:600c:5845:b0:427:abed:3602 with SMTP id 5b1f17b1804b1-42abd2457a0mr295855e9.24.1724173864584; Tue, 20 Aug 2024 10:11:04 -0700 (PDT) Received: from localhost (178.126.90.146.dyn.plus.net. [146.90.126.178]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-429ded19839sm207698495e9.6.2024.08.20.10.11.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 20 Aug 2024 10:11:04 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess , Eli Zaretskii Subject: [PATCHv5 14/14] gdb: 'target ...' commands now expect quoted/escaped filenames Date: Tue, 20 Aug 2024 18:10:44 +0100 Message-Id: <731f6112a25ffba0b1d4581ec5bf6d952d0d1bdf.1724173729.git.aburgess@redhat.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-10.4 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org This commit changes the 'target ...' commands that accept a filename to take a quoted or escaped filename rather than a literal filename. What this means in practice is that if you are specifying a filename that contains no white space or quote characters, then nothing should change, e.g.: target exec /path/to/some/file works both before and after this commit. However, if a user wishes to specify a file containing white space then either the entire filename needs to be quoted, or the special white space needs to be escaped. Before this patch a user could write: target exec /path/to a file/containing spaces But after this commit the user would have to choose one of: target exec "/path/to a file/containing spaces" or target exec /path/to\ a\ file/containing\ spaces Obviously this is a potentially breaking change. The benefit of making this change is consistency. Commands that take multiple arguments (one of which is a filename) or in the future, commands that take filename options, will always need to use quoted/escaped filenames, so converting all unquoted filename commands to use quoting or escaping makes the UI more consistent. Additionally (though this is probably not a common problem), GDB strips trailing white space from commands that the user enters. As such it is not possible to reference any file that ends in white space unless the quoting / escaping style is used. Though I suspect very few users run into this problem! The downside obviously is that this is a UI breaking change. Reviewed-By: Eli Zaretskii --- gdb/NEWS | 4 ++++ gdb/corelow.c | 23 ++++++++++--------- gdb/doc/gdb.texinfo | 9 ++++++++ gdb/exec.c | 7 ++++-- gdb/testsuite/gdb.base/batch-exit-status.exp | 4 ++-- .../gdb.base/filename-completion.exp | 3 +-- gdb/tracectf.c | 11 +++++---- gdb/tracefile-tfile.c | 16 ++++++------- 8 files changed, 47 insertions(+), 30 deletions(-) diff --git a/gdb/NEWS b/gdb/NEWS index ee453ed376d..aa66cd55491 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -45,6 +45,10 @@ remove-symbol-file -a ADDRESS multiple terms, e.g. 'function + 0x1000' (without quotes), previously only a single term could be given. +target core +target exec +target tfile +target ctf compile file maint print c-tdesc save gdb-index diff --git a/gdb/corelow.c b/gdb/corelow.c index 136f29ea2e8..0f87d565afc 100644 --- a/gdb/corelow.c +++ b/gdb/corelow.c @@ -614,7 +614,10 @@ core_target_open (const char *arg, int from_tty) int flags; target_preopen (from_tty); - if (!arg) + + std::string filename = extract_single_filename_arg (arg); + + if (filename.empty ()) { if (current_program_space->core_bfd ()) error (_("No core file specified. (Use `detach' " @@ -623,25 +626,23 @@ core_target_open (const char *arg, int from_tty) error (_("No core file specified.")); } - gdb::unique_xmalloc_ptr filename (tilde_expand (arg)); - if (strlen (filename.get ()) != 0 - && !IS_ABSOLUTE_PATH (filename.get ())) - filename = make_unique_xstrdup (gdb_abspath (filename).c_str ()); + if (!IS_ABSOLUTE_PATH (filename.c_str ())) + filename = gdb_abspath (filename); flags = O_BINARY | O_LARGEFILE; if (write_files) flags |= O_RDWR; else flags |= O_RDONLY; - scratch_chan = gdb_open_cloexec (filename.get (), flags, 0).release (); + scratch_chan = gdb_open_cloexec (filename.c_str (), flags, 0).release (); if (scratch_chan < 0) - perror_with_name (filename.get ()); + perror_with_name (filename.c_str ()); - gdb_bfd_ref_ptr temp_bfd (gdb_bfd_fopen (filename.get (), gnutarget, + gdb_bfd_ref_ptr temp_bfd (gdb_bfd_fopen (filename.c_str (), gnutarget, write_files ? FOPEN_RUB : FOPEN_RB, scratch_chan)); if (temp_bfd == NULL) - perror_with_name (filename.get ()); + perror_with_name (filename.c_str ()); if (!bfd_check_format (temp_bfd.get (), bfd_core)) { @@ -650,7 +651,7 @@ core_target_open (const char *arg, int from_tty) thing, on error it does not free all the storage associated with the bfd). */ error (_("\"%s\" is not a core dump: %s"), - filename.get (), bfd_errmsg (bfd_get_error ())); + filename.c_str (), bfd_errmsg (bfd_get_error ())); } current_program_space->cbfd = std::move (temp_bfd); @@ -1521,7 +1522,7 @@ void _initialize_corelow () { add_target (core_target_info, core_target_open, - deprecated_filename_completer); + filename_maybe_quoted_completer); add_cmd ("core-file-backed-mappings", class_maintenance, maintenance_print_core_file_backed_mappings, _("Print core file's file-backed mappings."), diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index f158d3dafb1..5ae581a0da3 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -16245,6 +16245,9 @@ Both @var{filename} and @var{dirname} must be on a filesystem accessible to the host. +The @var{filename} and @var{dirname} arguments supports escaping and +quoting, see @ref{Filename Arguments,,Filenames As Command Arguments}. + @smallexample (@value{GDBP}) target ctf ctf.ctf (@value{GDBP}) tfind @@ -23166,11 +23169,17 @@ An executable file. @samp{target exec @var{program}} is the same as @samp{exec-file @var{program}}. +The @var{program} argument supports escaping and quoting, see +@ref{Filename Arguments,,Filenames As Command Arguments}. + @item target core @var{filename} @cindex core dump file target A core dump file. @samp{target core @var{filename}} is the same as @samp{core-file @var{filename}}. +The @var{filename} argument supports escaping and quoting, see +@ref{Filename Arguments,,Filenames As Command Arguments}. + @item target remote @var{medium} @cindex remote target A remote system connected to @value{GDBN} via a serial line or network diff --git a/gdb/exec.c b/gdb/exec.c index acd9b04337b..cae08868f8e 100644 --- a/gdb/exec.c +++ b/gdb/exec.c @@ -143,7 +143,10 @@ static void exec_target_open (const char *args, int from_tty) { target_preopen (from_tty); - exec_file_attach (args, from_tty); + + std::string filename = extract_single_filename_arg (args); + exec_file_attach (filename.empty () ? nullptr : filename.c_str (), + from_tty); } /* This is the target_close implementation. Clears all target @@ -1120,5 +1123,5 @@ will be loaded as well."), &setlist, &showlist); add_target (exec_target_info, exec_target_open, - deprecated_filename_completer); + filename_maybe_quoted_completer); } diff --git a/gdb/testsuite/gdb.base/batch-exit-status.exp b/gdb/testsuite/gdb.base/batch-exit-status.exp index 3721fd56018..51514640958 100644 --- a/gdb/testsuite/gdb.base/batch-exit-status.exp +++ b/gdb/testsuite/gdb.base/batch-exit-status.exp @@ -92,5 +92,5 @@ test_exit_status 1 "-batch -x $good_commands -ex \"set not-a-thing 4\"" \ set test "No such file or directory" set no_such_re ": $test\\." test_exit_status 1 "-batch \"\"" "1x: $test" ^[multi_line $no_such_re ""]$ -test_exit_status 1 "-batch \"\" \"\"" "2x: $test" \ - ^[multi_line $no_such_re $no_such_re ""]$ +test_exit_status 1 "-batch \"\" \"\"" "$test and No core file specified" \ + ^[multi_line $no_such_re "No core file specified\\." ""]$ diff --git a/gdb/testsuite/gdb.base/filename-completion.exp b/gdb/testsuite/gdb.base/filename-completion.exp index 7ba055b9ae7..95a9fbaa857 100644 --- a/gdb/testsuite/gdb.base/filename-completion.exp +++ b/gdb/testsuite/gdb.base/filename-completion.exp @@ -301,8 +301,7 @@ proc run_unquoted_tests_core { root cmd { prefix "" } } { proc run_unquoted_tests { root } { # Test all the commands which allow quoting of filenames, and # which require whitespace to be escaped in unquoted filenames. - foreach_with_prefix cmd { "set logging file" \ - "target core" "add-auto-load-safe-path" } { + foreach_with_prefix cmd { "set logging file" "add-auto-load-safe-path" } { run_unquoted_tests_core $root $cmd } diff --git a/gdb/tracectf.c b/gdb/tracectf.c index 25a8fe7ead9..b4997f8589f 100644 --- a/gdb/tracectf.c +++ b/gdb/tracectf.c @@ -1111,7 +1111,7 @@ ctf_read_tp (struct uploaded_tp **uploaded_tps) second packet which contains events on trace blocks. */ static void -ctf_target_open (const char *dirname, int from_tty) +ctf_target_open (const char *args, int from_tty) { struct bt_ctf_event *event; uint32_t event_id; @@ -1119,10 +1119,11 @@ ctf_target_open (const char *dirname, int from_tty) struct uploaded_tsv *uploaded_tsvs = NULL; struct uploaded_tp *uploaded_tps = NULL; - if (!dirname) + std::string dirname = extract_single_filename_arg (args); + if (dirname.empty ()) error (_("No CTF directory specified.")); - ctf_open_dir (dirname); + ctf_open_dir (dirname.c_str ()); target_preopen (from_tty); @@ -1162,7 +1163,7 @@ ctf_target_open (const char *dirname, int from_tty) start_pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter)); gdb_assert (start_pos->type == BT_SEEK_RESTORE); - trace_dirname = make_unique_xstrdup (dirname); + trace_dirname = make_unique_xstrdup (dirname.c_str ()); current_inferior ()->push_target (&ctf_ops); inferior_appeared (current_inferior (), CTF_PID); @@ -1722,6 +1723,6 @@ _initialize_ctf () { #if HAVE_LIBBABELTRACE add_target (ctf_target_info, ctf_target_open, - deprecated_filename_completer); + filename_maybe_quoted_completer); #endif } diff --git a/gdb/tracefile-tfile.c b/gdb/tracefile-tfile.c index 66769216a6b..b59b5c73325 100644 --- a/gdb/tracefile-tfile.c +++ b/gdb/tracefile-tfile.c @@ -462,24 +462,24 @@ tfile_target_open (const char *arg, int from_tty) struct uploaded_tsv *uploaded_tsvs = NULL; target_preopen (from_tty); - if (!arg) + std::string filename = extract_single_filename_arg (arg); + if (filename.empty ()) error (_("No trace file specified.")); - gdb::unique_xmalloc_ptr filename (tilde_expand (arg)); - if (!IS_ABSOLUTE_PATH (filename.get ())) - filename = make_unique_xstrdup (gdb_abspath (filename).c_str ()); + if (!IS_ABSOLUTE_PATH (filename.c_str ())) + filename = gdb_abspath (filename); flags = O_BINARY | O_LARGEFILE; flags |= O_RDONLY; - scratch_chan = gdb_open_cloexec (filename.get (), flags, 0).release (); + scratch_chan = gdb_open_cloexec (filename.c_str (), flags, 0).release (); if (scratch_chan < 0) - perror_with_name (filename.get ()); + perror_with_name (filename.c_str ()); /* Looks semi-reasonable. Toss the old trace file and work on the new. */ current_inferior ()->unpush_target (&tfile_ops); - trace_filename = std::move (filename); + trace_filename = make_unique_xstrdup (filename.c_str ()); trace_fd = scratch_chan; /* Make sure this is clear. */ @@ -1121,5 +1121,5 @@ void _initialize_tracefile_tfile () { add_target (tfile_target_info, tfile_target_open, - deprecated_filename_completer); + filename_maybe_quoted_completer); }