From patchwork Thu Jul 4 14:20:56 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 93363 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 C959A384A47E for ; Thu, 4 Jul 2024 14:21: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.129.124]) by sourceware.org (Postfix) with ESMTPS id B1DAC3861022 for ; Thu, 4 Jul 2024 14:21:19 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org B1DAC3861022 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 B1DAC3861022 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=1720102883; cv=none; b=JXkd5iD4ILlr5lW30i7gEqObgUb33XIdnrctNqE6mjVUGbWTzaGc7poRRBW+hCyEJHJz5w+JBUIx7ZG5pxH9sT+dcFai8T1SIO/3ShRFu9krt5VnxQZn5b+6dFP2LV0vKhz1iWDSAU/yyM/VGeMCIPWxQSvUstAjHS1mWIpf0TM= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1720102883; c=relaxed/simple; bh=FSdBmLrL/TqK6TmGlHo9m8LLEjLCPGLGVGrS9kunQmo=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=bPoTBalD7NCKBvOUELdZ3ClAgv1r0TwnA+TmcWdDn+ZFmM3sE8UA3Sb/5J6nB5Lc5nRkoq/Kj3r+vwxwAB+9C7GEWlXjUY3biDu5KqUwyWDvNO8U09nojxGa1Fy9uTlx8ONmbLvw2nSLwwVfTLctnu06Vc8FTHt/d275PxWSGVQ= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1720102879; 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=PTrSu0NOFECgBSVQSsaoW8kSUS0V/IuqCi52bmkdcVI=; b=Y5qMY4SUlpDv5IMNmOmNcBOoU3sOHgn89BS/nSVakNlL/mst8IXL8pWhjeWSvoKW86jSkr rq6A4GC3VrseGb2NQ2CqTcfBqq6B3x3DbHRkz/8wRta3Ow8JlTObyK+Wad8vrMdUVxNk1x 2/LCun34BQaEnMzlqXQRac8PAlQNE2U= 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-197-9h4vwsLOOrOyZ4jrFppx3g-1; Thu, 04 Jul 2024 10:21:18 -0400 X-MC-Unique: 9h4vwsLOOrOyZ4jrFppx3g-1 Received: by mail-wm1-f72.google.com with SMTP id 5b1f17b1804b1-4263fff5eaeso5253135e9.0 for ; Thu, 04 Jul 2024 07:21:18 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1720102876; x=1720707676; 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=PTrSu0NOFECgBSVQSsaoW8kSUS0V/IuqCi52bmkdcVI=; b=oBj0GjzIRZGi4lUXWQxkeAUwfCONPbMshKStdrLxm5fL3Px2jhEA54m1hdigNznlHO csG4XpVlfdljD0+Mjx0dAKIt0Z8SM3q+MR9leTgm+SrPK/Lrux1/ZNQgV40sJvVNVj0F Mu/vX/jtoHI53vTX0EV2TuPwNS57YwQ1JIctP6zgxnX93kGAwz1aSZX9pauHHqIMaLvA 4vdQyvnzHV+Pm9kpQauDWYUyrVpeJ5SWDb9hAWFigzi/KJqQpTsEdI95l3IikhsjNxSs xqY0TuoZDFnROx9cOwsksPLsOjuhZ74Dgi3FsbuhW4HimZBjMB7BtMcsZjDYh8yleNpP 6pig== X-Gm-Message-State: AOJu0YzG7cha7U/JjGTj4bYudll3ausHR4jJi6aW6/g20Bx8yKCf6JYU F5WxBpeBq7D34ks8xc/39FsmVZ/xt4gZGXuumj+fCALoey58DiUa9/2rIlzdh/Hy8vfngFURp4Y vfiFFALG2AsUHMOGNxS/+xHyfSWLk/l2hZulhYldRe+tiAFIVl3w/1E8iTjqNDkjxFzX+RMhKu3 JD4Bke+ZwRvjEmTKYqz54tnX/Pysqzr2sqVeTTWMOO43I= X-Received: by 2002:a05:600c:1ca4:b0:426:4765:16f7 with SMTP id 5b1f17b1804b1-4264a3dc17fmr13251935e9.21.1720102876007; Thu, 04 Jul 2024 07:21:16 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFHDB8oVh9+/hglTzTK4te9sjDslfNBf3NR2pY9gZLsm3Gf+62vvfMCOjwtY4oUZpCkvJQW2Q== X-Received: by 2002:a05:600c:1ca4:b0:426:4765:16f7 with SMTP id 5b1f17b1804b1-4264a3dc17fmr13251665e9.21.1720102875422; Thu, 04 Jul 2024 07:21:15 -0700 (PDT) Received: from localhost ([31.111.84.186]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4264a2fc49fsm26386955e9.39.2024.07.04.07.21.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Jul 2024 07:21:13 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv4 01/14] gdb: split apart two different types of filename completion Date: Thu, 4 Jul 2024 15:20:56 +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=-11.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP 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 b0510b4b409..91b5364218a 100644 --- a/gdb/symfile.c +++ b/gdb/symfile.c @@ -3839,7 +3839,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\ @@ -3853,7 +3853,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 dfe19c9410d..b0417163600 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -1656,6 +1656,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 Thu Jul 4 14:20:57 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 93367 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 06338384A46F for ; Thu, 4 Jul 2024 14:23:10 +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 ESMTPS id 692D4384A80B for ; Thu, 4 Jul 2024 14:21:21 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 692D4384A80B 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 692D4384A80B 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=1720102884; cv=none; b=VpTcavUQBvhCQZiSAbON0PjffBwfo/79R4LGynq9BoOPdhrV/pTM+BRuQ0WQlrvEnpJXNpLVDyR/7M/58Lud0twwBGUgVIEs4dlS8/zGwIHiExv/MzOXvUaXZvwCcGVuPB+KIuMeMv+0LFRMBmtijI2OcfijtdF82tefpurWGEI= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1720102884; c=relaxed/simple; bh=M2tpeg4Jka+7TRMNmaJY5LXXt4Pst5ZxlbexIaJoWdk=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=SGNKrmWCpkTOq0zV4SJnYla5+Kk/OTjEj+C3rqlEKOYAnupg76Jo5DmdoNoVtEKtgyhoWX2GvGavbpL1BE7A/27Fgm/qncIZ3ez32ClfhCKFOAy3acNZsGF23djrcD9KC2lCcMYirvEn1K0UmmA+Z/sx68Z1EW7DY8k87axgado= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1720102881; 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=b3Cmb0AgdpnseSJ+x1+k+liH2oqb1S1Hsn7AfnnWn1U=; b=ZzKXiIR9Csly3/m789VfJlyxKidTXxZE6x2faC4gpCADsH3ZKjJLn3m1qyS/YQPbAqWKbp bPBvtdHedGA5jx6PXZc4LojYJEd7GP4DJBXJdW34A8IIiv9fvWx+BXy1AiLjbYJUyshUW9 dq0uoorb50DOp03NcFnX9YHcux7pCkw= Received: from mail-lj1-f197.google.com (mail-lj1-f197.google.com [209.85.208.197]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-630-Y3pwvbVMNOiYzUwsEHRIHw-1; Thu, 04 Jul 2024 10:21:19 -0400 X-MC-Unique: Y3pwvbVMNOiYzUwsEHRIHw-1 Received: by mail-lj1-f197.google.com with SMTP id 38308e7fff4ca-2ee806f5a66so7049281fa.2 for ; Thu, 04 Jul 2024 07:21:19 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1720102877; x=1720707677; 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=b3Cmb0AgdpnseSJ+x1+k+liH2oqb1S1Hsn7AfnnWn1U=; b=EALX2rFtSPVSKcbLyOqb76uU7v0RLmIIHUyZM3Xc1M6PtHVAKYI9BoPexqvqkJdGRG dggTU/BvSV7TkGhdW15v9RFzbQkOrv8LVi7BUU4nmHCvW2Yo3mtvi5Lc/NKA9iln9b13 fojykKNfBlcc1WGEe+nIHMODeVu8vzcDZobKeAjdZmr65Hb8d4KEpFPNngNOIoCoHvta 0MAUC8qKl42Tgq7UvkX3HJSGXRFOeCOOGlJv1gme5yhyDvZAZ9/u8uiOuodk9rhS8dM9 bCy2qUFKQFTQUQvVKb/bM4cDEs4YVht+MMVkYQZ649oshu/4Gg0sB0tPmOYl+giAjXzW bKRw== X-Gm-Message-State: AOJu0Yy5v3Mr6fDmcmp6ow7JTDbCuevyuhJ6OWdIhef+Wkmmp7xse7wV 2Kp/W6PTb4NwyVnyTg/eeHWnk3pH0Cqm0wxU0dX9kzqxZcp3kxc/V6EUvL0Z+8m0E1L/ND+SzaH nSYh+igIAu9VwbXAQPu09XleBoUON+hgiO+h9yVqrqtgo50jnWmLjxAFHmtVtaOUtYl5xCPJ6v1 XuQjrHcp+wKmiOoOd2HnOioEw+OTftc2Hj4zTuWQBKNos= X-Received: by 2002:a2e:9eca:0:b0:2ee:4e67:85e0 with SMTP id 38308e7fff4ca-2ee8ed223a7mr12344011fa.3.1720102877246; Thu, 04 Jul 2024 07:21:17 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHIXqIkdS7KqwdPcE/opzm2F5v2FUYtRlxBACOJtCy6Hs1LEctUHvBoOm0jYmG2UdqlhpNDLg== X-Received: by 2002:a2e:9eca:0:b0:2ee:4e67:85e0 with SMTP id 38308e7fff4ca-2ee8ed223a7mr12343701fa.3.1720102876549; Thu, 04 Jul 2024 07:21:16 -0700 (PDT) Received: from localhost ([31.111.84.186]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4264a1d169dsm26716045e9.5.2024.07.04.07.21.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Jul 2024 07:21:16 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv4 02/14] gdb: deprecated filename_completer and associated functions Date: Thu, 4 Jul 2024 15:20:57 +0100 Message-Id: <22ee24f32962efc80e45d9facb526bfb23b318a9.1720101827.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=-11.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP 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 afc98eb1f58..0b1c496c03a 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 a973518ac5f..b8a79bdc409 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -15094,14 +15094,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 3af794cebaf..c69eddc3412 100644 --- a/gdb/cli/cli-cmds.c +++ b/gdb/cli/cli-cmds.c @@ -2638,7 +2638,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\ @@ -2804,7 +2804,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); @@ -2893,7 +2893,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\ @@ -2977,5 +2978,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 88531a21781..24d911dbb10 100644 --- a/gdb/compile/compile.c +++ b/gdb/compile/compile.c @@ -327,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_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 71514d5ba66..a6ff5bdf3ca 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -3112,7 +3112,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, _("\ @@ -3128,7 +3128,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\ @@ -3162,7 +3162,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\ @@ -3312,18 +3312,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 6a197679902..ce25fcade54 100644 --- a/gdb/inferior.c +++ b/gdb/inferior.c @@ -1112,7 +1112,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 797be95a8da..03f7c8ef9c1 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 eb62d186fa5..26f77fa353e 100644 --- a/gdb/record-full.c +++ b/gdb/record-full.c @@ -2891,12 +2891,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 b25445713fd..5895478ec92 100644 --- a/gdb/record.c +++ b/gdb/record.c @@ -821,7 +821,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 9e528d3f705..f97bfd1484f 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 91b5364218a..1bf3f47a6f5 100644 --- a/gdb/symfile.c +++ b/gdb/symfile.c @@ -3871,7 +3871,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 4f210441623..bdd7f19d60f 100644 --- a/gdb/target-descriptions.c +++ b/gdb/target-descriptions.c @@ -1762,8 +1762,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. */ @@ -1947,7 +1947,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, _("\ @@ -1956,5 +1956,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 Thu Jul 4 14:20:58 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 93364 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 D0F1A384A47D for ; Thu, 4 Jul 2024 14:22:21 +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 ESMTPS id 3BA4B384A4B5 for ; Thu, 4 Jul 2024 14:21:22 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 3BA4B384A4B5 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 3BA4B384A4B5 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=1720102884; cv=none; b=XyedIHCOSRJCTa/ujzzPKCdMlledhXsSqk2vqJkSWrWpGP1VwhMGa0DQkfoyjDUsRVac/mfMGs7MeVmL5sai3vkRZuFVcbAI3r7wMjV03Bxjt2emUXptsKOVxhwU1V8fE81E7QDb+NGUR9nMRH6ollIr7bltrpis2FKodwaK95E= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1720102884; c=relaxed/simple; bh=nBP3BqVxycwd99sTcr/YhC2/TCFUpkF1fXPdPCpsnxE=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=al1KnvrUYDKnDYDPmqBWi7r3dl3leBwFcC374iVU7vezicaOZgPNE8Pps3GI0BTGElPQxsjFyBKFhmI+lgea5AsYm5pqhJv3CzMY470oXk6DScjIRqwGjARVOr9gwcRHRnar0B0ivLmANsfIcYzXffi45Z5tY9jbckWjBrLrALs= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1720102881; 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=Y9/D/O6LiZc9TW6G+OPIXClqUlxParnMxR0ke88Lf6qEOQcmgROe1Ey5v3e22qrQSzMaNl mxrKz26ZRNkpV0aOP6DlxzjOT0aR+Xn5P3xM4e/XmprGycpO/wBzEaXDtYK6g5pPnKSJtR KOC+bYQ5ghkKTIlFTbof02ErrzaZ3Sw= Received: from mail-lj1-f197.google.com (mail-lj1-f197.google.com [209.85.208.197]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-91-Jtaymgp3OamphnKvoRnfFA-1; Thu, 04 Jul 2024 10:21:20 -0400 X-MC-Unique: Jtaymgp3OamphnKvoRnfFA-1 Received: by mail-lj1-f197.google.com with SMTP id 38308e7fff4ca-2ec4df4e2e8so8170811fa.0 for ; Thu, 04 Jul 2024 07:21:20 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1720102878; x=1720707678; 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=P8kbgsfH8GqS8m8vE1tA9O4TslmNDJ0GVptMZYJ/poYXZoYWcIL6hPo5AZ0lLX6tZ1 uNNW8HYAVCXZwh+vpDPGCYPWleCg4dRcCxy9K/aV2DlZ28w1JrdiJz5kUDwR1cdqVcuH ++XeUdZn2oYoq7l3hlPgetsi+2MNKe0iGvyUYYxvGW/PONRAFgkbPYxWqDZgaxiVstfR Sfu6UX7n/fDV1A4xFNFiLU4sczX+/mp6tea29ysk+o3fh8ZZUCZxoCNRTv345iITXwXI 9yANreBEe3M7ORKahYZ/1ru1DsDGcBaRx+SrGsZfrvJPHBFHSB8vPoliQ9+gR53THoD1 kK1g== X-Gm-Message-State: AOJu0YwRq/VNrATMI5TL+fpUm9BktRo34CnRDwv041kniRax6RER27P1 deM20FmmbDVxLM4Ca1E7HYCezvzPvSe2TRYNDAGaMMv92vSZB3coC7Yj9URfNvs0V1VTUlnenje tfC6PQtFvOkoWrs8HOANmd9I+HZJtR/uDW6FM5opkP0CIdK6oFpZRwBxJtw46oLBFTwGLlj7Bna zDWR9woyVn6ghVlAtPSWQcTtJUSHWSTvgSiV1lBdV6Fn0= X-Received: by 2002:a2e:3506:0:b0:2ec:4df7:8cef with SMTP id 38308e7fff4ca-2ee8ed42586mr12896741fa.15.1720102878330; Thu, 04 Jul 2024 07:21:18 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFIJY/GMcOIW+fnjFktgCFjcRG/acS7kY/R+5bqMvsj+G2mh+dcJcICjiCOHaSeCDJK1tKxmQ== X-Received: by 2002:a2e:3506:0:b0:2ec:4df7:8cef with SMTP id 38308e7fff4ca-2ee8ed42586mr12896501fa.15.1720102877775; Thu, 04 Jul 2024 07:21:17 -0700 (PDT) Received: from localhost ([31.111.84.186]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-36795d1fc9csm3962108f8f.83.2024.07.04.07.21.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Jul 2024 07:21:17 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv4 03/14] gdb: improve escaping when completing filenames Date: Thu, 4 Jul 2024 15:20:58 +0100 Message-Id: <1a3a72ce5649840817b81270021055044566d3dc.1720101827.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=-11.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP 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 Thu Jul 4 14:20:59 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 93365 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 B7FD1384A41C for ; Thu, 4 Jul 2024 14:22:50 +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 ESMTPS id CBCC4384A441 for ; Thu, 4 Jul 2024 14:21:23 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org CBCC4384A441 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 CBCC4384A441 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=1720102886; cv=none; b=bMAnMmz8SOr6OhXYUr9VInLninDQ2pnIZxNwQv9oTVkSovBGh3j7ct3arqgCYwwFVDQVeOIC70AoVZdB4mAN+aDsOzKwlhiuvWCaVi/srpwUC4RoEyNiu/0Cfb4RxSdEemto49/Y9HQrysUQo4MHAMAb8DPgjDZh/o2FUVgkFsw= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1720102886; c=relaxed/simple; bh=+1QQb81QyGAzdyC2XiYu6J/pfci1/AY++nrNP3BT4R0=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=OPGCzxZGXbwUDM6FbaaC57nYpTOW3pgDHUza/9iSbGMwGHZws5zhAP61dAYe2Gu0jZyJ1pL36k+J10g9SgIJhCN5EyxT57O5HW3UfM1sqcQ1GJpxvUPSSKyQ7IRu85q+GnnpErS2dOLYM/umtWgO49GR/FBil5AVanalk28E444= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1720102883; 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=p91xA7KC5mpRV1abmLsYc5iNhv7nL++hEhtJfCusNwk=; b=OqfPlNg/ZaZULI1VtU+vl4hvz7F27J8kgW89JUKHmP/aLeJnwplzrtSfytdzO46Ylyzjum XvNSScWSH0G/5vKY46r/DYgVBbjcsyKt7+Va89A3G1YsjMhiCpQ1Ajga1a3b9U4fVYLMDD M/L7J7CpEEMwPmOMmSPsjrY22U7HBc8= Received: from mail-lj1-f199.google.com (mail-lj1-f199.google.com [209.85.208.199]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-595-xTyXZO8yOumXZoDCFJ76MA-1; Thu, 04 Jul 2024 10:21:22 -0400 X-MC-Unique: xTyXZO8yOumXZoDCFJ76MA-1 Received: by mail-lj1-f199.google.com with SMTP id 38308e7fff4ca-2ee4a63e95cso8490561fa.1 for ; Thu, 04 Jul 2024 07:21:22 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1720102880; x=1720707680; 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=p91xA7KC5mpRV1abmLsYc5iNhv7nL++hEhtJfCusNwk=; b=AUxYutoKt/1yllNiCyrKK+xnobVveBFiN2MR48WmmsGTalP+WU1Rsweq2Mdil0ZmSh 9lzYqr9b2tZIF5E4t58mFYXhsTGQ/PuokW3Jw56SumAE8nBxpCX07Zx9CDDqAMmCTw+d eVUN+cQ4HdTyExqSS4p4Yhordp3Ey9fZ8QEGX+RkiEcGaKdJzBQlcPqzhT5ylzDcV/N5 jzikqUfVSDx1OuesdeEx9ttRlnqnYjSL8DLkYsfhlBc3aZqNzs4LcnTINZyBQV5GHMy2 hjSugncL2vfCFQT17lD33Wsnm5gmAOkPD6W+tj1gXep4KeNOAY/yrUKqlToL4VvTSmo2 nYpw== X-Gm-Message-State: AOJu0YxAotQXhbraFtgSSs8FLXqfI29DGanpPv/MxURsvOkj7Nut8kJ/ AYrAUp5BPcgcd483fAzhYebqs8MudFd7FvGBfuwyaZi+VI4JjGmcusP+tq2be/5ANM7VW/nRzSK C2Xiw7WKG++ZcCjkpVuR9KSoH+8KCZR2rNPJzanjh9Rk5cp1q58OMxnfBLDq7hj6zkGcObGL+VG 7Slk+ArDMVEkNaxiJcBsgcKRSbVj6fYuXjV2eVGgUNxg0= X-Received: by 2002:a2e:818d:0:b0:2ee:8777:f86b with SMTP id 38308e7fff4ca-2ee8edd3edbmr12069861fa.35.1720102880206; Thu, 04 Jul 2024 07:21:20 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGUp9zwq3wEohCyGY7JIZWynuQIu9fWYaWrCI+pKdt5M9TJUE61rIherJCk5l7zeK0uraVfBQ== X-Received: by 2002:a2e:818d:0:b0:2ee:8777:f86b with SMTP id 38308e7fff4ca-2ee8edd3edbmr12069661fa.35.1720102879787; Thu, 04 Jul 2024 07:21:19 -0700 (PDT) Received: from localhost ([31.111.84.186]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4264a21cc59sm26331825e9.25.2024.07.04.07.21.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Jul 2024 07:21:18 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess , Tom Tromey Subject: [PATCHv4 04/14] gdb: move display of completion results into completion_result class Date: Thu, 4 Jul 2024 15:20:59 +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=-11.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP 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 c69eddc3412..73a650a3e62 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 Thu Jul 4 14:21:00 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 93366 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 39FB0384A415 for ; Thu, 4 Jul 2024 14:23:07 +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 ESMTPS id 056BB384A45F for ; Thu, 4 Jul 2024 14:21:25 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 056BB384A45F 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 056BB384A45F 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=1720102888; cv=none; b=huaDlPcY6wk6wgl6c9n+EN3F/KDgsSAjupM4IQpO9KQD/m7Q/oUZwWGskaAzCQstYHBQX2fME735OSRfkcuYQEp4U0RUgRQ1cuAbBl4/UaXX4cfdWv7qGpHY/0iJ6QKLy6XixXBzXpAOXqlIIRCF7AEQbOxgPa98hFSrwAoHmkQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1720102888; c=relaxed/simple; bh=fxnBwevF27AhRqv7f06I57/57ZR5jZTPrVFBflIt8HE=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=DwhlUhHYxJdivCD2gatvCEwIlLvt62CRRc+TQG2cC2zs0NTi8B4zc7Io5M4M8HozbJKl/ey/6GN9KVDkNjT3MRwwIHylJfA3/cLKHYVK4iHJxDQTS6dcPQiSXSq6eOjSvoi/l2bUEaKFtVPn8wTyQbS+CcmxegG1+rR/XUnLhYM= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1720102885; 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=FOE2KQ7ONfT+gV9OMqAYIfxdMYrNRTxpROsCC/jUUe7sml8GxV6QsSuQUqNCEOvLTDWiKP Sug8Od6s383/NaClR7hyjus69C0iuwCUffdf+LgMK6DeyKjb3zzXoGp5pIYRPGHIkgNbaA xgB8i3w61F28FJc7J7lC7Hl//RhnqCw= 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-134-tBdxZWkaNXmKgzFX4vbRrg-1; Thu, 04 Jul 2024 10:21:24 -0400 X-MC-Unique: tBdxZWkaNXmKgzFX4vbRrg-1 Received: by mail-wm1-f71.google.com with SMTP id 5b1f17b1804b1-424fb2df2bdso6908525e9.3 for ; Thu, 04 Jul 2024 07:21:24 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1720102882; x=1720707682; 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=lSWiF7onZElojN+KoxOrw8wPeiitugBUgncupbExweqX7Rhl4wDHK8XRxuDh8/hLEH TXhQvu6/3Pz9bwAvwDzgBsg8BjpEPXUekEuXWILlamVt2/RbEZz4B0rHiFDsCT4VTeea 5YKwG95EUAI44eUhNeJ0s6MDP34FDiAdMtA6i5e8A8oJNUXfCso6J0ami/b2Yqr4rxFr /3daA+k3UPm7hM1VyDkFGZUU/WLwyHHJDQgc47Wf0H/PkL29q7Vz03yjCfs1mPTL2TP+ JKkF4dhjGIg0oHLqt/YtgDn+bDYEenM2Yh/Zdnyb+oKmqk8PrKz5HrltBqtgFzphd3gS 8UzA== X-Gm-Message-State: AOJu0YzSx9rZTYgMnSZ2Hi7/Ki8m33EGHzWxHJMaoS0t27ytZQYeQYRP 9Ut8Jr+8s8r43ujUAr/CST72Oo4WS9+wzzI3MeWHBjtL+chEUQR5SmAgB/1mIoKxB90idAaypyD /C5g6KpT0qujxgRYL5VxhFw4Tih8ZiNwtsRURFAtY32WnHyt5sYFbT6X9tbji/eIBgm8TRq6mGA 0UkmrcIIBohAIMOZrGvxtzVXVTpFBZwJSzh0z3GAApKlQ= X-Received: by 2002:a05:600c:331a:b0:426:47df:7d5f with SMTP id 5b1f17b1804b1-4264a41f864mr15184355e9.40.1720102882000; Thu, 04 Jul 2024 07:21:22 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHEAdeKssFEWVnybZ0ySu9A3zcMFW/bSM/h3onS+te1dJqPcjcJTljcCTRLijXoE5ZBa0hAZA== X-Received: by 2002:a05:600c:331a:b0:426:47df:7d5f with SMTP id 5b1f17b1804b1-4264a41f864mr15184175e9.40.1720102881527; Thu, 04 Jul 2024 07:21:21 -0700 (PDT) Received: from localhost ([31.111.84.186]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4264a1dda61sm26538105e9.19.2024.07.04.07.21.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Jul 2024 07:21:20 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv4 05/14] gdb: simplify completion_result::print_matches Date: Thu, 4 Jul 2024 15:21:00 +0100 Message-Id: <77c38da2452bfa3fc1206b5ab592b11073a01450.1720101827.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=-11.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP 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 Thu Jul 4 14:21:01 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 93370 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 8CFDB384A47B for ; Thu, 4 Jul 2024 14:23: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 ESMTPS id 05EF3384A45D for ; Thu, 4 Jul 2024 14:21:29 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 05EF3384A45D 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 05EF3384A45D 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=1720102891; cv=none; b=PXtoOLbkmUfmpLG8dMbnE+fGFPhaEFjm4ItqDZxAyRMYGdriv8pekfU49j/9/ZPY0IZ6ZAxpSAIdgmbXkmiol8jJicWyFy7ggztT2xZ/kaekKcfhYBbmcJe9WVZZ5RwJHA2sMGkABSKk69F03UEW+HTFj0MJOyCzFoTMRiKnmSQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1720102891; c=relaxed/simple; bh=EZap3VNs33GIylLeL7vx0hdOzxqTRDXNAAfEeQC576E=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=qdgiFzztMgjsyPy0NF18n26MmIYsgv2hXM4WLzMwFUL/M1a/2mvb0kkaAgYa8PIEkD+sTQq5wy48TJOHSeXsxMa8TrBxgeN5jGNhqSTCkQm0yRi+G/wKVV+VTkho/9aUUoo2yLJe9G0Zi8QPzCLAPajPYCDW/N5wJ5GlinBHcsA= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1720102888; 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=a3bt2fpyD5spZUUfCvuQxO0jrHeKFCNBak9zcgPgQ5W4/soAz763gZ7m6WuEiwP9uguqYa rAygAgRg90KEcSoB9BAcanVfIki04VH8zNRLT/QFvR63/GDDBxjW6FmxEheBG3lQtIPRqr CXP806928BkGgTm3GcoBYpg5DDwhx4c= Received: from mail-lj1-f200.google.com (mail-lj1-f200.google.com [209.85.208.200]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-609-Atf8egAqODCMsTraFNzsDQ-1; Thu, 04 Jul 2024 10:21:27 -0400 X-MC-Unique: Atf8egAqODCMsTraFNzsDQ-1 Received: by mail-lj1-f200.google.com with SMTP id 38308e7fff4ca-2ee86eda4e4so7186461fa.3 for ; Thu, 04 Jul 2024 07:21:27 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1720102885; x=1720707685; 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=WGz4pLBpe4+YNzcPA3akUBTN6pg3XccN6stHy2ZnfqtrcgmjhT7GhA1V4STtp+Ew5O Nj1Pq8lh3zzmbr1uIojyDl1qibqfq+JZ/8BSeRUMnPk9OmbL+5Po3j1+DeIbcxHa2Pw2 waATH/5rFGdsyDYyDe24g747NL9Ry580DndPmontDOW1/swk1qj/ShwzfkF51c9jYsUZ gyLa1oq8oHfXuY6NkPCPpmoACN4Ok2BKlqZxH2sRGQlTo45ri6Mb1+cNlhNTHHnai5/F n6gEwL3e5Lxx1vJWUYfaerVDtKCMzhMcXvdFl1o+tPZSW/Ut+uf9qA/ejXyZduBJ5R+j 9WWA== X-Gm-Message-State: AOJu0Yy5yJPsDwlg+TxIA85ff0wNPqlj181cWTK6DChqM9+PYmGoW1lt d8N2SrNdNYADW9aEVvIF0bBHtq9+aoMlZdeJ5oyXGLlS5j8tuJVymck/62GrOFfypfkk+sad0g8 4MrL2oS0UYnQpXQ2mjRsPa61maPepSUAEw6fY0g1pEkAyF6Cd68v2nVntGK4MCk/KeSbxGNwAFa 7X/u4gfAB5pBe8iz3X8CoZhEH0iksCt+r75DiURbPQoKg= X-Received: by 2002:a2e:900b:0:b0:2ee:86c1:f743 with SMTP id 38308e7fff4ca-2ee8ed8cd97mr12795381fa.15.1720102884887; Thu, 04 Jul 2024 07:21:24 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFxtLaK9UNGUwsjNKjN182b8icJKGw3d+g04gZAIQvcrVQNDU2zq7uC3GiRmrJmeEefNoBqww== X-Received: by 2002:a2e:900b:0:b0:2ee:86c1:f743 with SMTP id 38308e7fff4ca-2ee8ed8cd97mr12794991fa.15.1720102884012; Thu, 04 Jul 2024 07:21:24 -0700 (PDT) Received: from localhost ([31.111.84.186]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-36798fafa0esm2660946f8f.74.2024.07.04.07.21.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Jul 2024 07:21:22 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv4 06/14] gdb: add match formatter mechanism for 'complete' command output Date: Thu, 4 Jul 2024 15:21:01 +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=-11.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP 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 Thu Jul 4 14:21:02 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 93368 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 20426384A424 for ; Thu, 4 Jul 2024 14:23:24 +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 ESMTPS id 0482D384A462 for ; Thu, 4 Jul 2024 14:21:29 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 0482D384A462 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 0482D384A462 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=1720102892; cv=none; b=CpbTMBxjamDqgycQ4nStAJB3qYEnW4Z0MJ3DCsneS6xculwhoHYMfW1AHz4crj6j+RPZrDJgbowa0QNcWlYjHlEA1nVdNoJRGFKSVZq+J1UdbE10CfO9T336f8EtPiGxuWudGk5VPOC3rM4e0PcBJ5+6apPt6TIiJgQ3+/nOVg4= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1720102892; c=relaxed/simple; bh=IcIT9gmGOTwa1DZeKtUYNzoTmKxP9RUXAgKr9y0WBIM=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=ltRycayi47kqAH4MXszzSf2wnvXilaXaiIouFHBfE/v+jVYMky05Q2rOwfOom/CSj5qc5ba+5wjLPQP40oah1RLVlPBVVAd6baaZQZNjRuFTlBE+wut40CIgxOTAzO+/Q7lGYJZBLSueTc4m7Q/79Q0mFR5m3ruqFar04HeBYTo= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1720102889; 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=TbehOSI2nYq4fwccUoE6cNcfIIAzr9eo/U2rTFwMSbT5ozvk+aygtjo2XVvV0hDKMnYYea URdgYNmEIB+mqTOefe6Ql+rl1mH/w3IxQzeqxRaaVpvtY1zv7nB/IQ7K5KslyTP2zPv/oU 9W4bFqZJ+WqYzRm4oHi5m+Ri/HLiO34= Received: from mail-lj1-f198.google.com (mail-lj1-f198.google.com [209.85.208.198]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-647-Yc4x66j2PmKYyuQO1UowHg-1; Thu, 04 Jul 2024 10:21:28 -0400 X-MC-Unique: Yc4x66j2PmKYyuQO1UowHg-1 Received: by mail-lj1-f198.google.com with SMTP id 38308e7fff4ca-2ee87546e5eso7707221fa.0 for ; Thu, 04 Jul 2024 07:21:27 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1720102886; x=1720707686; 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=fKTzsg642oXHJ/bi4WbqwlBExazPRTVisFdQ7Ys6YN9Aml3FMFnNrKFz/azJDfoUXk JVwycOsXbk0j582yTTqvyOMWVyYLV8iz06IsC5bHvbouPYtGURfbkecmp4BdJtkBvppI lcmukqns1Ya+hzamz2zbpCuZvSuyoPeDhYMlPtxXfYelF0DFsFib6RFT8sf0FXr001Sd Ar6zkTR7sZBz5NWQBLCtM1u/d6OGknngXy0gwD/MUk8rrxlxE46PYXVKT2tHcaCmUCkn 8aQxzBm+mCiYhoPDCOPj0rPlS7auGgNs58b/L2uOakwoUDeV5+7bqzeM4ZB8ZD7f+TvC PfOA== X-Gm-Message-State: AOJu0YzbiCWVevfwYcRv3trkW2aF8oF7NeMP8JN4NimWaP1p9c7lZtYT p+Wvg/mMNZ5vNFHJntOEApEvblFBcxci6xTIQ+yA3jc5AVbsabP54a+0otcx58EtlLoQ4/lr1Rl yX7UT8IS251zrs1PpEKIPco5rrSqYqJsMkJ6xh2ma24d3IVJmqyuwBQAwbM5xKdNmy/ps8anzVw rRs6uV4qI/VKwsHK6LUlBV5WoGUHR6ELnOC5SQ/T/l7Qg= X-Received: by 2002:a2e:9b89:0:b0:2ee:4da5:be67 with SMTP id 38308e7fff4ca-2ee8ec7b181mr12051781fa.0.1720102885941; Thu, 04 Jul 2024 07:21:25 -0700 (PDT) X-Google-Smtp-Source: AGHT+IEyi7/MwSSn8QiK7TcPmI8jw3I6uxs/VFwUOrMDzNsgmri94anuDDg4GzkIypD87BPoNQ6RiQ== X-Received: by 2002:a2e:9b89:0:b0:2ee:4da5:be67 with SMTP id 38308e7fff4ca-2ee8ec7b181mr12051691fa.0.1720102885506; Thu, 04 Jul 2024 07:21:25 -0700 (PDT) Received: from localhost ([31.111.84.186]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4264a2519a4sm26241025e9.35.2024.07.04.07.21.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Jul 2024 07:21:25 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv4 07/14] gdb: apply escaping to filenames in 'complete' results Date: Thu, 4 Jul 2024 15:21:02 +0100 Message-Id: <31ffc76781297e0ebfb843ad7a3d789752183680.1720101827.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=-11.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP 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 Thu Jul 4 14:21:03 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 93373 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 1889D384A418 for ; Thu, 4 Jul 2024 14:24: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 ESMTPS id 9DFFB384A478 for ; Thu, 4 Jul 2024 14:21:32 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 9DFFB384A478 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 9DFFB384A478 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=1720102895; cv=none; b=c/B1LjVz+PVjsDOPdXiAzMJAl8ynxseuW3C3E4Edo2+4H85kS4SkpZ3isSEsIu/9Q1gpP1K5oOrgy4oQNtjQSIgn/T8FdVBfUdGwVJ1OHRr2i3JI2EQB3FJMF3y2QIhdQNMAIy4vuV4Udq8qXg6sMrJyEOo8erJimvqyA2ujS0c= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1720102895; c=relaxed/simple; bh=Y1BK1YTWLB+3Wq0yZQHIeSkYh6+SW46mhkY++yJaoHM=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=u65OUHqeyajNj6kyOA3/49BaGBmwJTGwo18mzGC4wX3d+5WZJapv60L3OZaN4IqYlAPzGfBRZtIpgqEW4Zgtzr9rTB3/RTunaiwQjIKBPW+3woSTKqpIdg6Y67I1yhIz4iuo6aRMOFGXYttkrTdbi97zqOllXZuXw/wPBCPvTcg= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1720102892; 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=ch3eJfIPDX3QNBlF9Tk2FQBuiasZsaMmIpqb6JYv6HSxyzmUMP6VGhBKW7g6z7Y3p2a7X5 mGnoJbZWUJlo+pr2I2osuQAvx7yT/JygpL4TTAP/fw6ZnFLxQmr4pdWQWtM2TMWvtMlSOL VIoIV+wZEjp/qKPtrqgi7tY2JPETQJA= 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-338-pBfJ_bFTOWGT0kgG93B0-w-1; Thu, 04 Jul 2024 10:21:31 -0400 X-MC-Unique: pBfJ_bFTOWGT0kgG93B0-w-1 Received: by mail-wm1-f71.google.com with SMTP id 5b1f17b1804b1-424a775ee7fso5082095e9.0 for ; Thu, 04 Jul 2024 07:21:31 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1720102888; x=1720707688; 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=BHwHuPNBmRAfHeq0jt941bQoF6DBCgA84qrQhkEOKxP7dBKREFEVoqkHihvM3d8QJL pSekRpuaxFyBmWqmci88pnjkBbEXRkAw3cvYzAEfaYej2mwB76Dbb7Fp8mr329cB+Ao4 BKV2CnBzNaq9lbpNWNADjEICYTdCBPa4vo43mzFwWyr90Yo3PVb46R4/iDq6oUEUB//N VVpActIzjPcagthRfX4fmlPpQe9M0i1k9R6P+V/zTq/UVFhBj6zSmjvf2zvNJOD53HTC CRhn681dI0KyvVKxEtrmo6MC2f7hhHjxcYADqjxD5XVzW5msktNfaoEMpXvfwQnYOtEG KneA== X-Gm-Message-State: AOJu0YwNoLiRRVBJuyyj/0PVeWTsPiHk8FcFeVIkPWLJC3VUb+A/xYSL opu+izcgfsp5dZgre+IlTyqzaWaltahNetmgQiRDLipSJnaHb2j4C5wzoUwsz61TJDfxlIMu1jU jPJDW1RuNVc9MtmJfRq1rNyzg16o0rBu/euS9HNNy4msMMGwZv2mi0RXDMBlLcPEEymbpQ0vUWn QbJh/UW+dxP1HULhTrTltQM6ILugtpoFayFVFHIz/QwqA= X-Received: by 2002:a05:600c:3b1f:b0:424:7992:c21f with SMTP id 5b1f17b1804b1-4264a3be2eemr16203375e9.3.1720102888477; Thu, 04 Jul 2024 07:21:28 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHND2dCNFL0K6RAR8rO585WfxhjCRM2q7TOHCQbHmYwYjMmfGkviCo7KV2fTPK5Z1bvl3prrw== X-Received: by 2002:a05:600c:3b1f:b0:424:7992:c21f with SMTP id 5b1f17b1804b1-4264a3be2eemr16203185e9.3.1720102888037; Thu, 04 Jul 2024 07:21:28 -0700 (PDT) Received: from localhost ([31.111.84.186]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4264a1d50b0sm26952665e9.7.2024.07.04.07.21.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Jul 2024 07:21:26 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv4 08/14] gdb: improve gdb_rl_find_completion_word for quoted words Date: Thu, 4 Jul 2024 15:21:03 +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=-11.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP 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 Thu Jul 4 14:21:04 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 93369 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 42C7A384A47D for ; Thu, 4 Jul 2024 14:23:54 +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 ESMTPS id 7F958384A45A for ; Thu, 4 Jul 2024 14:21:34 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 7F958384A45A 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 7F958384A45A 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=1720102896; cv=none; b=B7mt0s2CnEHn0wb1XP0lCbAmz6hVW+tB2qddlqoMKhNJePoitkngKpdhnuhJ30r5ckalUZoytVLxW9IBJs8KWH07dgZM0wGb0vaC+V9mUSpzkzNyyISq+8ZSfxXmgP7wD1uO++J5xqnit1iAxJlD3YvfbH51mGZ/zeTknC3Br7o= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1720102896; c=relaxed/simple; bh=gc7CF8aqrfSljFS3I/XtZE0s2W20VlQKZlJYMgKbG5Y=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=pEhsADlK4BH+0IA867W+kxJxrvOkJ0Gvky4yRucT5TUmQlvT4g3afh2wWyWlFExl+mMssbJlfJTPb0rOpfJFS64dJ9teTfCLcq62TkeXGdTHfanSRkremdmdl3JTOyMH7yY/JU2257A4oiWz0kEcKOfLtMo14PR1ymnTJi6/ZUc= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1720102894; 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=Oq4YM5KwiY3cs136PJtgiGS7SfAX1V+srmmu0RGKogZBFRBk5CGpL47wSyqWeOIyUYLjJ1 t5j4piuM3sh8E+MTuHTtEQfYtlCK9ihJ64CMi/V/sKhoDZeXnak4Se6UsE3sisFgORu+1d dQtkjfSuwpA7Q8vlTOH6BNhbWxmQd+0= 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-148-zSRnO1tqOT-GPfq3fVKbvg-1; Thu, 04 Jul 2024 10:21:32 -0400 X-MC-Unique: zSRnO1tqOT-GPfq3fVKbvg-1 Received: by mail-wm1-f71.google.com with SMTP id 5b1f17b1804b1-4257f95fe85so5141585e9.1 for ; Thu, 04 Jul 2024 07:21:31 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1720102891; x=1720707691; 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=Fewv7w9Cz48hnQXsKWstsYGG/b1xR3B98xcWdJ4tFg1VKHiHC8hoR8YuPcoUIZWy4r L9j7dfUrkBNiPiV2+9ZJcLCrhN21mN9p+37TC7Tioy/r9A4myjVv2EFVVRMWJYZyaDIz LLLNaK/IAw4xPLsZxgQ017NKkbsEESBoLWNVsXTMD4jhEEF9LQEOiDKIfz6mHV2H0GU6 8QRTnoNAJjWz6M2qsd7a2WZHbTJnzSZH181I4gKLwQZlBOKENaeK24u52AVu50EjAKmf y2NMQewU55XTpwmNzPxyvMRoWH4s6DoEPQRa/RMDcu/1c+5aX3/fN60/rGeOoRu+J0wX JCsg== X-Gm-Message-State: AOJu0Yxi9V14oOCVW1zq45zApgySI1EWO55kevd7Qt0xekmHkRu193zA M2ZejYOzs+mJ1ay5Apxi7WrFWMKI5QKpBByNF0CbmWC0r6yR3ucDnIDiUdD0wh5lQKrBxGOhHp+ UvZmP9uD9MKsDje2QI4d09QvpdUDZ1NN1/mWv6fM19X2tGGg8OIUZTAzjXApSbahlfT1n7lro9a KM9X8/MGvWgN06+pYhbsj+Dtq1GVBZ4NhvuiH0m3qyK00= X-Received: by 2002:a05:600c:21c8:b0:425:5a26:a12c with SMTP id 5b1f17b1804b1-4264a3e1cb5mr12758095e9.13.1720102890846; Thu, 04 Jul 2024 07:21:30 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHY3m0XK+NEUsGVVYkVID0Q2RDQPxv58cFyQOQZ1RfE2IpvSrQ/4/qkWQolSw6AeWYtUUnvAg== X-Received: by 2002:a05:600c:21c8:b0:425:5a26:a12c with SMTP id 5b1f17b1804b1-4264a3e1cb5mr12757925e9.13.1720102890515; Thu, 04 Jul 2024 07:21:30 -0700 (PDT) Received: from localhost ([31.111.84.186]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4264a1d1650sm27160705e9.2.2024.07.04.07.21.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Jul 2024 07:21:28 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv4 09/14] gdb: implement readline rl_directory_rewrite_hook callback Date: Thu, 4 Jul 2024 15:21:04 +0100 Message-Id: <4fa1ad1a88e5e025e710745eb5ae456b8f0ae884.1720101827.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=-11.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP 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 Thu Jul 4 14:21:05 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 93376 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 D40A9383FDD0 for ; Thu, 4 Jul 2024 14:25:27 +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 ESMTPS id 80FF8384A45B for ; Thu, 4 Jul 2024 14:21:36 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 80FF8384A45B 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 80FF8384A45B 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=1720102904; cv=none; b=lLoiPabOKzYnpQpbEtMywg2tzSqEL93EAsNY0YDTDBieOixBQCsWQBt7G2x/2zMz/5uVkfCNdW/L2JJTpRpnVkEenjFSDnEQwKh0ufZQEX/1bSjLN1fa+nW776PFbNnlJxVg1b/dAJ9ASt6pWDECC7iwOq6Mb1Xr4+N35hClFog= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1720102904; c=relaxed/simple; bh=ECphfNatEkMncKOxvPGJKr/LLGOU/qOusGwYVbuG7rw=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=xqLo3wcBfJS8zjxitiCj7wnK4erw4QcA2up15Ap/+MK5RTI3mpSejwIb5aMFJy6NSxyCr/0iGxHKcRj6ajfQixOKd6w7eshYaT/HAba8OdxpgNgI0++qX7zMWqsN20Pkr4k2prSgKGncajnn0709i6Kd1OMTJcDb2PeUIx+0a/Y= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1720102895; 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=N0uyiUSmfT9wQlNEK2t3Oxsg75snkyJIf/EYSYwKcRI=; b=QgvpCvoukM6/gPGc50ybqYJYnrOmYKAD/0q9ngbXOkKVUCKYSxseUCvh981CNO8hTZQCMr AJ4IWRGbJk6n2QsjehtSRQKNb4joOnLZ4VK+WwaGDpPbzVXunwopd6l0MenKmOZTV9vl13 Pwiz7UlDrV9djz376J7KvjiAYyGOiaI= Received: from mail-lj1-f197.google.com (mail-lj1-f197.google.com [209.85.208.197]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-159-0jyDwuJTOAyhssb2DKXO-A-1; Thu, 04 Jul 2024 10:21:34 -0400 X-MC-Unique: 0jyDwuJTOAyhssb2DKXO-A-1 Received: by mail-lj1-f197.google.com with SMTP id 38308e7fff4ca-2ee49ce152eso7507801fa.3 for ; Thu, 04 Jul 2024 07:21:34 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1720102892; x=1720707692; 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=N0uyiUSmfT9wQlNEK2t3Oxsg75snkyJIf/EYSYwKcRI=; b=NSL53fTgNXXWUUu6uC1EuWCXMx8xgLzcfvUAR+ugO/au3a+pK1Yf7wpz129u4FLwZn uZv2UxWU+aAnwwQgCbyINyybHCJkZws1ctMhC8himTMLtQDKgo31kpqGvlVuIfoqdWUU QUlS9QYAPHEvM8wk9MrYrbrimyMwVlGSEcL2nrJ0pv/N/+ZrQftYStjpF9D+eT0r49/x gAuimihFbsAK366qsEg+D4BRFy4nmmJv9i5AwmhCzWVIcXfpWEq5hMe7rBjkD6zJy8z3 SOCi1bQy2Afzsm0rlGhJ4RlwEQiZy2WtMo8GuHVycxZZ5Un+kfLH5/x/lSqmYT6ETNUJ VKQA== X-Gm-Message-State: AOJu0Yx0Tr4MAgC/vHBdLqZu9kYEYE2Qxjp0jai8tWkwbizV1rNnptT0 ZGuDNBts5GOmx48PIsTywZ50FYdHY+pTmcIWPBFdBRfjFS10qQa6jpI42IFFJtuWrWI+VboPw9b j1xnA38bTbkA4bEo3mkTcIDp4wujqcfFSEIc2jHtvVezTJcpHOkBa1QqqITPEXst0HJaqa8Aeti lA+7M0s4fPZh7u4zlrOF3oDxSv9tVzzECkXzUKIJkMOH8= X-Received: by 2002:a2e:9083:0:b0:2ee:6cda:6380 with SMTP id 38308e7fff4ca-2ee8ed4259cmr13050491fa.18.1720102892328; Thu, 04 Jul 2024 07:21:32 -0700 (PDT) X-Google-Smtp-Source: AGHT+IEZ1UaJboMp1ouo2z6lmiFrh2kUCxDwzHCwsrWzuRt1/TjWwZZdHMiJw59XJMMmWMZoV9aVgw== X-Received: by 2002:a2e:9083:0:b0:2ee:6cda:6380 with SMTP id 38308e7fff4ca-2ee8ed4259cmr13050301fa.18.1720102891925; Thu, 04 Jul 2024 07:21:31 -0700 (PDT) Received: from localhost ([31.111.84.186]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4264a21d2adsm26312485e9.29.2024.07.04.07.21.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Jul 2024 07:21:31 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv4 10/14] gdb: new extract_single_filename_arg helper function Date: Thu, 4 Jul 2024 15:21:05 +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=-11.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP 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 17498e04312..f80e72a6ddd 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 Thu Jul 4 14:21:06 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 93379 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 B196F3884609 for ; Thu, 4 Jul 2024 14:25: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.133.124]) by sourceware.org (Postfix) with ESMTPS id 46628384A477 for ; Thu, 4 Jul 2024 14:21:37 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 46628384A477 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 46628384A477 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=1720102904; cv=none; b=chSHhlHGYyCoCPNkc0JRzmtVOfKUD3JVlSme3LTS8J2TPw7cwthvDTXZqthfM63UzOTRxSn4b2yX54whvKqYK88qKdKQbtU1MRrhU7rcusH8gziadtbq0n99zIAg5YGy2qLkDQ78pHuOF/OtrmItNWwyyd2NL9XTwjfvyOYLvhw= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1720102904; c=relaxed/simple; bh=nFxpyuMfB17zFgF8ol1z05O1rx4ukW7DAIiUGJerwa0=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=iXuSD89sLGfYmZhlVG5Cu9N7HzdcVuc8Ds5rhEBrz9IhS5Vk9FxBWAN3NplAzWubI0u2ENrulInJSarsIFR7l8XIjYfELARv2L6G+gOQeV0bm/rsQVdmsXiHBQ4txbKWKOQUf4EdhgIR4Nrrb60FeTqCAhvwLzGT8Tmd7IEsg9w= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1720102897; 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=DxQO3gNIlqg0fi7n2VIlhQ3ewjfYfvxbgW6DmrQcK/doV3y5r4ju2Ep1/TGlAlaHLKNH3h ufQSpUIKfTY+f9ZSk84UOaO9XNjJaPG9HvuvdwKN/nYRrLQTYjfvTjky7RtB4NGNnva1m0 U7ULCC2EuZIgb9r6h33KkL3DXsGNPtw= 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-552-4DqXhuGrNuWKmtC-5qf_Gg-1; Thu, 04 Jul 2024 10:21:35 -0400 X-MC-Unique: 4DqXhuGrNuWKmtC-5qf_Gg-1 Received: by mail-wm1-f69.google.com with SMTP id 5b1f17b1804b1-4258675a6easo5264335e9.3 for ; Thu, 04 Jul 2024 07:21:35 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1720102894; x=1720707694; 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=oGgiz22ZV2eFKwEYgX4EKVCBqocpF2oPKMlNcnehtcKR7I1Oefkx8Nxj+YXNBwhSSa dnuc/VjuBWcyyO1JfUtm5xTuLGfKGm+wKt+QJ1yHHsNdPfNLsto+PfHMtgKyPRIFIszD r/H4WsHweY7+x5KPV4AfdzqC95C+wNqevdoAQmUpQteYo8DfZFyNj6HZ0FpU1YppCmdD 5C/2YP4PvVGJdJdRCi8sOhG/hlRY3jeZeGcNGbGEAtX3NScfm6AOot4MmhK48CoSBajd lzQ5geerDLmSRpP2/KsBKCq4DmiX0RakPF82PEnVqlFg5fiDsdlNYxpu3mA42Pxb+gAb yrMA== X-Gm-Message-State: AOJu0YwZvD9DKWQ6QuiZ25oyZQiCquK6o1ZB+WYUx0WmSxR1M2wIGrz4 CMD5my28a3X5FOGoM+naHW/Tl7eD2IGLg8vjgRuYe/0tzFXLmQ3n0ijzv1L3W2pMGOhF+gHDirS TIWp5H3T/OSlbiAgH172hySkLP9U0tUpsiFFkuEu5D3px3azRjNQ4F1sJo64Z0z/s+N0dVPpN4T yHIJV/EVLXqYWP64cB99IlvuVzUZ9KT5l2Tbu5EyOr86E= X-Received: by 2002:adf:f3c2:0:b0:364:348:9170 with SMTP id ffacd0b85a97d-3679dd63d98mr1393175f8f.54.1720102893969; Thu, 04 Jul 2024 07:21:33 -0700 (PDT) X-Google-Smtp-Source: AGHT+IEBzqKOX/qxDJs6Gvu+JG0cmbCe1DUm9PIFFuDs24RNGtloBm4VC0f9unWzai0kpn+U2kxvpQ== X-Received: by 2002:adf:f3c2:0:b0:364:348:9170 with SMTP id ffacd0b85a97d-3679dd63d98mr1393155f8f.54.1720102893549; Thu, 04 Jul 2024 07:21:33 -0700 (PDT) Received: from localhost ([31.111.84.186]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-3675a103d62sm18544279f8f.105.2024.07.04.07.21.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Jul 2024 07:21:32 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv4 11/14] gdb: extend completion of quoted filenames to work in brkchars phase Date: Thu, 4 Jul 2024 15:21:06 +0100 Message-Id: <29b081fc05157a7e97a2c2423883bf8c49d66713.1720101827.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=-11.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP 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 Thu Jul 4 14:21:07 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 93372 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 CA1BF384A472 for ; Thu, 4 Jul 2024 14:24:34 +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 ESMTPS id 31C76384A465 for ; Thu, 4 Jul 2024 14:21:43 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 31C76384A465 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 31C76384A465 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=1720102908; cv=none; b=EPJuokGPOxYpWMawWy5Ci+KuDnkRnf6SXe+af7PQXyodMeQWculqqPtDj5PjvTSvHdSnG16Rmr5lveHye4DVr85P+33G/r4IgxyC7qNeJLXrQVM9byED5wGBTLygUKJigjQ26dvlS8/RqN8eHLjZ87h1U9ePlqkStibd4kFPX7M= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1720102908; c=relaxed/simple; bh=cu16xqG6sjPLrWZ6mRgyD4RXvMAeZMpuDSvVshVmXI4=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=QSvwcKyBmTzIQetuO1Aic/GzvKgm5Emwecf/lbPPgHRypmtOXuYWckUQgqbR7eKwaqgwVlankG8awfpEQmYuU69HvcBIP2JFsbZih8O0S67mKBa4SVzY6AJOx4EcmRC7XQJKZkIhUOrgrcspEuN7Cn6PdyPVLeYzyXn8wR/XF3I= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1720102902; 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=2Saz/swoY8eOlp4lAE0mAj7Lje8lsBU4ebJDJ6O5zlM=; b=ZnpXTvBUvigj5qXUp1Qs5ikKEabs0uB3f8Vr+kdg77blKdLpU4GdpqlwGiRfcdGoWlynKb Src862VUXI1Q0QsyKPdlmYSUv7ADi/m2vVEPNat13Kvc8r/pVCXYqd6bmj0IkL9iL+TvNv WVgNI5myHUfhX9Je9sUptFzS10RfoeQ= 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-224-h9Bxr1IoN12IWsVmel71qQ-1; Thu, 04 Jul 2024 10:21:39 -0400 X-MC-Unique: h9Bxr1IoN12IWsVmel71qQ-1 Received: by mail-wm1-f69.google.com with SMTP id 5b1f17b1804b1-424a775ee7fso5082675e9.0 for ; Thu, 04 Jul 2024 07:21:38 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1720102896; x=1720707696; 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=Lt3Kp34CvY9wXr6HefPV/EF99vlav7DgO9rEqLvEz0Q=; b=ntIfnMiPhJ0slC5QV+U2eYprEb3V+zvcl4riyHWmZGsRrrLuYLK8nZZb67cuJvu0qg XTFwEZU60DFkhvGb1nI69laenzZSDRiaQP6VM5k/eC3ppHlU7rhmpxLR/2j9TF11mHP3 nFrOmIlIbxJD9XKVgsgV4AdKfHecGJgG/Pu+zCGFJ3aw8SsNIF5i6uwZaeFz6DCzsTTJ CNJY/84Du6i7Uusx1GeJCEzrzoP8zfexBfv7/WEkMXOAxNfjmIyWqV4bl4wN8BLKJ8C2 qHWNm91cnj9yOHvwxBiIWfxv5CQEN045BnLkoXV5A7hTgLH8zClZn/x5FmBHAZmi4IXf nRTg== X-Gm-Message-State: AOJu0YxOofe8/BuOGlgsX2r1BGZlpNNxkiX0I3Fw3pgqbFgPP3KYIn8v 8B21SFs26XUuCXb9vHd+bkIlQiClUC6iaVMz6xnO8lOP4IR+eQ2J2e0sP6pKH+OjB5qPcPUrW8o fmvlWaCujBLsY42Dt5RsJTVJsy7PGoItqPYhAnK88bjEVsD3eyt3Jgfy21CaZfRczypyyut//iD ilTdpK78FlC+LKxtOwfdGrPeC6EyO9Qziy1xzBGTr2k/c= X-Received: by 2002:a05:600c:1989:b0:426:4b90:1e91 with SMTP id 5b1f17b1804b1-4264b901fdbmr11788305e9.24.1720102896016; Thu, 04 Jul 2024 07:21:36 -0700 (PDT) X-Google-Smtp-Source: AGHT+IH+FWpNVgpLjeXuAYzfUX6amMtdLk/bDd8ZCu9JSsgl1+u2CCw5Ua/ZQpWR99xvpgSf08ojoQ== X-Received: by 2002:a05:600c:1989:b0:426:4b90:1e91 with SMTP id 5b1f17b1804b1-4264b901fdbmr11788025e9.24.1720102895316; Thu, 04 Jul 2024 07:21:35 -0700 (PDT) Received: from localhost ([31.111.84.186]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4264879e491sm17359645e9.0.2024.07.04.07.21.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Jul 2024 07:21:34 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv4 12/14] gdb: add remove-symbol-file command completion Date: Thu, 4 Jul 2024 15:21:07 +0100 Message-Id: <8531118d503847cc0a02b9634ead556a3ed7f0bb.1720101827.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=-11.5 required=5.0 tests=BAYES_00, DKIM_INVALID, DKIM_SIGNED, GIT_PATCH_0, KAM_DMARC_NONE, KAM_DMARC_STATUS, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP 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 --- 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 47677cb773a..8808fb3e1f6 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -13,6 +13,16 @@ This may cause breakage when using an incompatible libc, like uclibc or newlib, or an older glibc. +* Changed commands + +remove-symbol-file + This command now supports command 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 86cd420832a..7261a5559c4 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -21885,6 +21885,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 1bf3f47a6f5..8789b216446 100644 --- a/gdb/symfile.c +++ b/gdb/symfile.c @@ -2355,39 +2355,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; @@ -2395,21 +2446,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; @@ -3855,14 +3903,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 Thu Jul 4 14:21:08 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 93375 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 0E9E0384A41B for ; Thu, 4 Jul 2024 14:25:07 +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 ESMTPS id 7F65A384A443 for ; Thu, 4 Jul 2024 14:21:40 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 7F65A384A443 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 7F65A384A443 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=1720102905; cv=none; b=PyRtT+svebCR5RSI2nHQ4+6XxfNIUcasIcrafW5IRnyg6S2lYT7yrsXxUA3QcwVo+P0Y6h+vvEvnhs5OC36rkGke9pxcc6nAK/5BnGsXOT7b6U6VU7i6up5UBWhLNSv6175nSBXdMevMoL7R2nzbcXk/8Xd5ezg5feCcblAHkHQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1720102905; c=relaxed/simple; bh=Ok5QGig7fqFhuPwl2YhpnQ/mWzHnfQVaqCA5BMJGWso=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=JG5GHasOyRtXQ548Y/1NgQ7VB4BvO1rZwpMXAvxV6uO6iZlAav+RSraj7l5y8jl8ZkxiXqUNr4sVuQlBkHHi6WOQ7Ou+fuPix1OMUHumQLqYuesAPbhKFGJfBV1lEX79B1t+7TFWaD/QcaQljNe4cQ3dgpdW8o1tS4ETqZpugio= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1720102900; 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=ANNtfIsUCnMTNjwSXTEfB3LwZFOs59+P877Vuq8ulgo=; b=MdQEiOx5rNlCCFqLlwjMbp3M5EXcU6ma5lhSEYZJ8KjHEDLPBXLJkHylUejtsKaqN6d3b1 MGrPqaNUXVHjUB2Ok0ShWsEx1BDmbhXBKPStgrYRuowYUr9yMWzYxd77sIxT4N+N/uwiwD DweJQJjhrgFxLiYoQzPkJnS9g+PoII4= 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-365-cr3nfRV8OoCsHEJViVC70w-1; Thu, 04 Jul 2024 10:21:38 -0400 X-MC-Unique: cr3nfRV8OoCsHEJViVC70w-1 Received: by mail-wr1-f69.google.com with SMTP id ffacd0b85a97d-3679aa0ee0aso460073f8f.2 for ; Thu, 04 Jul 2024 07:21:37 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1720102897; x=1720707697; 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=ANNtfIsUCnMTNjwSXTEfB3LwZFOs59+P877Vuq8ulgo=; b=gj3YJJIuIx0LXywNjOzH+BvnugdBHgCwHT+b3j6IxVqDuHmYYnTtZuT/BVOCGKL2/h 9Pcl/NdFbfheCO/CFEgQRTGyt8OIAQqvfmq08TtUX5dtvWn/anm+O8P32yHj45Msbirl zQ1MCbNIftR5Fkz8yTpx7eSMCEOP7Wx2eQhRpUxlp27cXSWRxPAjFy5EIrS8o0QOU4eI N2uFUxw2kWZH712OmUE5yvBQ89yu6LTc2Rl77nkoSwwHSwtfMC5fYcKls+9YU5FNFHvj m6bfn1K7vZgBSzb54MUXBjoV536B2J90++p6j7TtgY3d/AGOXT6MJly03LJD/xgFzuvh HdDg== X-Gm-Message-State: AOJu0Yzb4ueaDl3LLZTFKkdQETGHstxi4ZXRefbyBU61w+JbXUlIqFkZ CsfB/z4YX6O/tb2rcm8oHaPvwTz/0Xdvcnj39fJuVwoopmM+qmBKTKGDAw1wz9/oa8CXzc99/FI tsG5+Zb4efY2wzxCwoUpObEVHZLCjFU0KVP71gLn+qc1/UFF53IErUOuJnuihhDj6Ljs6IGuzkJ PJXZNg38kSKUdjCOVaslk5YpN+ZYOx2e52qeCfMi4YD2M= X-Received: by 2002:adf:f0c2:0:b0:367:9769:35a5 with SMTP id ffacd0b85a97d-3679dd103f5mr1350987f8f.7.1720102896842; Thu, 04 Jul 2024 07:21:36 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGJGIzabtpe7KVseoEbZxlsAIDCVMRT1JO0xLjz0xonnFHrhS/Xs8uIlGtr2JiT4vAwLF7ooQ== X-Received: by 2002:adf:f0c2:0:b0:367:9769:35a5 with SMTP id ffacd0b85a97d-3679dd103f5mr1350965f8f.7.1720102896312; Thu, 04 Jul 2024 07:21:36 -0700 (PDT) Received: from localhost ([31.111.84.186]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-36796351169sm3674562f8f.95.2024.07.04.07.21.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Jul 2024 07:21:36 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv4 13/14] gdb: allow quoted filenames for commands that have custom completion Date: Thu, 4 Jul 2024 15:21:08 +0100 Message-Id: <351179c8d62d8dbd971679c1322757eb35ff4713.1720101827.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=-11.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP 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 --- 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 8808fb3e1f6..4a830a61cda 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -23,6 +23,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 with white space or quote characters. If the argument + contains no 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 24d911dbb10..b5aac495563 100644 --- a/gdb/compile/compile.c +++ b/gdb/compile/compile.c @@ -302,14 +302,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); } @@ -327,8 +326,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 7261a5559c4..e35cf45ec31 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -21337,6 +21337,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 @@ -22783,6 +22786,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 @@ -41779,6 +41785,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 bdd7f19d60f..65d0d563e7f 100644 --- a/gdb/target-descriptions.c +++ b/gdb/target-descriptions.c @@ -1693,14 +1693,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 @@ -1708,26 +1709,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 @@ -1738,13 +1737,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); } @@ -1762,8 +1761,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 Thu Jul 4 14:21:09 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 93371 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 13529384A470 for ; Thu, 4 Jul 2024 14:24:19 +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 ESMTPS id A2AA5384A44B for ; Thu, 4 Jul 2024 14:21:41 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org A2AA5384A44B 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 A2AA5384A44B 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=1720102905; cv=none; b=NuoYNMwfQURnOHJaWYx+caUPUfrhIlOXmWroeKfyeRT5nYGaAKVMB7sbYSa8XBIQzl1MdyzqKVf/wRfugy3qDUASOgBqtyEfUHCBuZybrsoCtKc7KnghSkZyLeVZhcYG5CmCFdCGpfOJD/oJ36+h/nY5uKBEDzBRb1vXGJjSYfI= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1720102905; c=relaxed/simple; bh=rpC2h9lPL2AbGnFBds8UAxZl8+HG0R0MUJYp04Ty7lQ=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=iSlNCyLSs/4CCix6w/iVvteHDafgCzYN4kf8NSoBG2ZeOKjQ23Re+cqY90c1lu7Fsejd53+SeDWSwxR9Es0SfZIOpTOpWXMhoaU4kQwbTCltcTpWUgczeH3osOOZkIXCHSp2z7+0CdJSm0unIsSWKqMYfoF+ruMYc8uJgdr/lCE= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1720102901; 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=+j3tvhRnjAaYaBfKXtBL3c3CEv0RqKWnfmMlbiEPe6Q=; b=Fbh01ZOxtOwABc4thWMw+4qHPh8wjYlvSV0OVy3PWdg/BwPJazjbisCO+5t3Zh23iPv7pv 56YhmLKQ4SlncAPulEydlAJrwWZNqHChLmfx2TDcISppVmeH04iasEDHvrKlUvZW5km03e 80izzvpgz2C4hdEZf/D81RbXnOle9o8= 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-261-7csmj8s4PTaFXSHbqrFNTA-1; Thu, 04 Jul 2024 10:21:40 -0400 X-MC-Unique: 7csmj8s4PTaFXSHbqrFNTA-1 Received: by mail-wr1-f72.google.com with SMTP id ffacd0b85a97d-367990a5796so473702f8f.1 for ; Thu, 04 Jul 2024 07:21:40 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1720102898; x=1720707698; 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=+j3tvhRnjAaYaBfKXtBL3c3CEv0RqKWnfmMlbiEPe6Q=; b=auO9dfnmIwX6o1MBO5krFKqECyndosMDzqfnGM6fcLXESnzH1HV+pTAiGs00rv3J4g kW+I05m4GKi0MYndDdv9i+m6o/fVKWYwYnmidoDbYYfQgn5Kx2GTg+EyYhPb+kuX9rhh oM9LMebyKgNfLE5OtefE1DhWpvUCrrBME9vSwMvBlkHBOCtsp1o4jR6PoC8GUvLPiwhg znFtKbf5w8OoY+lBIIJDRFH7sWlHSK9A5K+pw2hz2NYeXOyM8muVxmVoT/unWRPiKxPZ l3maC6gZ8z9Ic6v1RI2f95/HZncKBxGYMJeofl5JI0wsCjZBVqwbmV9uY90L1s9lj1Lx rkHA== X-Gm-Message-State: AOJu0YwyPyfkWyJybaZ49eurFlACIqF/ZDnXeN6H7k6R1qCnDedKls0d km4OCWwaPk+awpQa7oCzVAJRkEhd67ShZbS7/v0/ft2d1qx9MDsZYubJ4Cv+ZARu/LPCVuCFZHr UNXhjIb/lJIO+bbZkSfUxRay+2mSjXwwGdBkkiURf02bGPxuK9yyqnNssgcWBKQcI58H464B6eC r2E4tUHN+18X74btztOAw9O2MKJmpeHq0LAdEY9cjUeUQ= X-Received: by 2002:a5d:608e:0:b0:367:9877:750e with SMTP id ffacd0b85a97d-3679dd3df99mr1289842f8f.25.1720102898192; Thu, 04 Jul 2024 07:21:38 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFvFuXCcCtx2UYC8Z9fFNCzInjV5iKdWQTR75AkUEbFUlXpgnat7we6Vy1+2BatN8itH8u3BA== X-Received: by 2002:a5d:608e:0:b0:367:9877:750e with SMTP id ffacd0b85a97d-3679dd3df99mr1289820f8f.25.1720102897772; Thu, 04 Jul 2024 07:21:37 -0700 (PDT) Received: from localhost ([31.111.84.186]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-367a43e9fbdsm300223f8f.103.2024.07.04.07.21.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 04 Jul 2024 07:21:37 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv4 14/14] gdb: 'target ...' commands now expect quoted/escaped filenames Date: Thu, 4 Jul 2024 15:21:09 +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=-11.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP 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 4a830a61cda..9058d62d1fb 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -23,6 +23,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 e35cf45ec31..d95e13f1342 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -16238,6 +16238,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 @@ -23159,11 +23162,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); }