From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id D16243857836 for ; Mon, 4 Nov 2024 14:46:19 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org D16243857836 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 D16243857836 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=1730731586; cv=none; b=qBMoRyPe/laHcwbAKKinnc2Ba1w7fvp1pInX64UvKEjz1jeRfYDBrFpOe5rJPpt6JF1ffh0xjXolkRjvSs5h3N6Sh01cDFX4stnYShWGUc5Fn+lLs4L7XZKwOFZDxRiOiUw3a+bNuP+78ftwNywg1oNL03SIMGfrpKgtzUWj0fw= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1730731586; c=relaxed/simple; bh=SCRJZ1whPDq+sOvafxi2nGO+6hZz+/1keJ9UGorHp9U=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=NVOLiDfJLudXSSKGIdq+pblr7BHRaBkU9frod5JHfNOw7TjksILwf6YfOStgqhqlV17pHG6lsma34ADwTYcam4ypRRVsYeJspoAJqqsYt0gJkR3be5V0eI4CtFwxZE2aeQJSM7pIsMZms8ynKJDm/KnKRsWmCWeV+d3Br804F8I= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1730731579; 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=FvmtrOvEasfcMBN8hNgH5HSdv4suxSeoPLLt/tqVhAs=; b=DgLRk1K+9mhczhQe5q3Dru2XfMAT1yL2MiW7IAgU94Mpka8GvCWBEJuKP114A8okp4ok3V IY1eG9MonHsF3dObbPCtnCNXm8vYsABPFhfjbL94Xf0cmHNPQkdAjNwb4mWbosYGtBha/V TA6/3guCgZXg2gqV5Rtn/Gmp6No+kkI= 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-643-JhOTL-EjPVKKctOdJwGydg-1; Mon, 04 Nov 2024 09:46:18 -0500 X-MC-Unique: JhOTL-EjPVKKctOdJwGydg-1 Received: by mail-wm1-f72.google.com with SMTP id 5b1f17b1804b1-4315f48bd70so30693395e9.2 for ; Mon, 04 Nov 2024 06:46:18 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1730731577; x=1731336377; 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=FvmtrOvEasfcMBN8hNgH5HSdv4suxSeoPLLt/tqVhAs=; b=QlF2riPeJ/IWfU0IrsZpQB6Zt77XySXTc7Vz/NjOeH7OAp94kiRYSk/tWg1+a4yGn4 H+PVNQkXsLkROHBOIruU8eSTnSpi1tEMMY40eTQ7grHDcwUVsD5wysIGSBC9G+w9ZW90 /M0ajvn8toZGxV/SQKjtA4T/RHprEJjmuFWY47jqRD1xQcqXmRhWwJps83Jtm4qjI3c9 yoll3FoDakQW5ptoY1wPu9djeBdIZg7MnNFiaiTPW+hphdTAbixsEGAwjvd7Bnve/LQR DaMRv99XK5bm/mYKGHlo0UzPM2/DW9rh/uDofxFuPrOG7GoCEh7uxx9TsOdEtjXqBT4b 96Ow== X-Gm-Message-State: AOJu0Yz6DfDaSlpnzMRmoZSacA/9Fe5JdHvWFttkphyFvVp4jWygMKMD YlPq3jiHBBhGT16PXX2id9QYt0SD0vakuphwxQeS7yo4hZ4NPlg7HxoG5E7VvPqrJZwQLzMIK8i pcSql9iIk/LDozBBhdISbco3W+YBFY2JnLhYOKrOGyLW510cear4rOcG6RG2ouujQmEGAxXH+Ik /1NOiXv9XrNgqHiu9UfZ9ajqQCMYa/kENMLAPeyI+2dJo= X-Received: by 2002:a05:600c:1c28:b0:431:55af:a22f with SMTP id 5b1f17b1804b1-4327b6f950fmr140448105e9.13.1730731576396; Mon, 04 Nov 2024 06:46:16 -0800 (PST) X-Google-Smtp-Source: AGHT+IFm9BOxf6ioufSphE0aTk4iwzFMIsiARJ6fL6G+Ya9w1QfxU9bZC8mtyKEYVsKTKK3qBaDV3A== X-Received: by 2002:a05:600c:1c28:b0:431:55af:a22f with SMTP id 5b1f17b1804b1-4327b6f950fmr140447165e9.13.1730731574288; Mon, 04 Nov 2024 06:46:14 -0800 (PST) Received: from localhost (197.209.200.146.dyn.plus.net. [146.200.209.197]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-381c10d429dsm13503499f8f.31.2024.11.04.06.46.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 04 Nov 2024 06:46:13 -0800 (PST) From: Andrew Burgess To: gdb-patches@sourceware.org Cc: Andrew Burgess , Michael Weghorn , Eli Zaretskii Subject: [PATCHv2 09/14] gdb/gdbserver: pass inferior arguments as a single string Date: Mon, 4 Nov 2024 14:45:53 +0000 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 Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-11.8 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_H2,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 List-Id: GDB holds the inferior arguments as a single string. Currently when GDB needs to pass the inferior arguments to a remote target as part of a vRun packet, this is done by splitting the single argument string into its component arguments by calling gdb::remote_args::split, which uses the gdb_argv class to split the arguments for us. The same gdb_argv class is used when the user has asked GDB/gdbserver to start the inferior without first invoking a shell; the gdb_argv class is used to split the argument string into it component arguments, and each is passed as a separate argument to the execve call which spawns the inferior. There is however, a problem with using gdb_argv to split the arguments before passing them to a remote target. To understand this problem we must first understand how gdb_argv is used when invoking an inferior without a shell. And to understand how gdb_argv is used to start an inferior without a shell, I feel we need to first look at an example of starting an inferior with a shell. Consider these two cases: (a) (gdb) set args \$VAR (b) (gdb) set args $VAR When starting with a shell, in case (a) the user expects the inferior to receive a literal '$VAR' string as an argument, while in case (b) the user expects to see the shell expanded value of the variable $VAR. If the user does 'set startup-with-shell off', then in (a) GDB will strip the '\' while splitting the arguments, and the inferior will be passed a literal '$VAR'. In (b) there is no '\' to strip, so also in this case the inferior will receive a literal '$VAR', remember startup-with-shell is off, so there is no shell than can ever expand $VAR. Notice, that when startup-with-shell is off, we end up with a many to one mapping, both (a) and (b) result in the literal string $VAR being passed to the inferior. I think this is the correct behaviour in this case. However, as we use gdb_argv to split the remote arguments we have the same many to one mapping within the vRun packet. But the vRun packet will be used when startup-with-shell is both on and off. What this means is that when gdbserver receives a vRun packet containing '$VAR' it doesn't know if GDB actually had '$VAR', or if GDB had '\$VAR'. And this is a huge problem. We can try to address this by making the argument splitting for remote targets smarter. And later in this series I will do that. However, I think that splitting and joining the arguments as we do was a mistake. The later patch in this series handles unquoted, single quoted, and double quoted strings. But doesn't really address parameter substitution, command substitution, or arithmetic expansion. And even if we did try to address these cases, what rules exactly would we implement? Probably POSIX shell rules, but what if the remote target doesn't have a POSIX shell? Why do we need to pick an particular rule set? Clearly, for backward compatibility we need to maintain some degree of argument splitting and joining as we currently have; and that's why I have a later patch in this series that tries to improve that splitting and joining a little. But I think, what we should really do, is add a new feature flag (as used by the qSupported packet) and, if GDB and the remote target agree, we should pass the inferior arguments as a single string. This solves all our problems. In the startup with shell case, we no longer need to worry about splitting at all. The arguments are passed unmodified to the remote target, who can then pass the arguments to the shell directly. In the 'startup-with-shell off' case it is now up to the remote target to split the arguments, though in gdbserver we already did this, so nothing really changes in this case. And if the remote target doesn't have a POSIX shell, well GDB just doesn't need to worry about it! Something similar to this was originally suggested in this series: https://inbox.sourceware.org/gdb-patches/20211022071933.3478427-1-m.weghorn@posteo.de/ though this series didn't try to maintain backward compatibility, which I think is an issue that my patch solves. Additionally, this series only passed the arguments as a single string in some cases, I've simplified this so that when GDB and the remote agree, the arguments are always passed as a single string. I think this is a little cleaner. I've also added documentation and some tests with this commit, including ensuring that we test both the new single string approach, and the fallback split/join approach. I've credited the author of the referenced series as co-author as they did come to a similar conclusion, though I think my implementation is different enough that I'm happy to list myself as primary author. Co-Authored-By: Michael Weghorn Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=28392 Reviewed-By: Eli Zaretskii --- gdb/NEWS | 7 + gdb/doc/gdb.texinfo | 25 +++ gdb/remote.c | 25 ++- gdb/testsuite/gdb.base/args.exp | 47 ++++-- gdb/testsuite/gdb.base/inferior-args.exp | 31 +++- gdb/testsuite/gdb.base/startup-with-shell.exp | 158 ++++++++++-------- gdbserver/server.cc | 21 ++- gdbserver/server.h | 5 + 8 files changed, 228 insertions(+), 91 deletions(-) diff --git a/gdb/NEWS b/gdb/NEWS index 7c3c02a4cd3..55547954c71 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -120,6 +120,13 @@ vFile:stat vFile:fstat but takes a filename rather than an open file descriptor. +single-inf-arg in qSupported + The new single-inf-arg feature within the qSupported packet allows + GDB to inform the stub that it would like to send the inferior + arguments as a single string within the vRun packet. The stub can + reply with the single-inf-arg feature to indicate that it is able to + accept arguments as a single string. + *** 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 eb2aff974bb..55be5876ce2 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -43425,6 +43425,12 @@ (e.g.@: the last program run). The program is created in the stopped state. +If @value{GDBN} sent the @samp{single-inf-arg} feature in the +@samp{qSupported} packet (@pxref{single-inf-arg}), and the stub replied +with @samp{single-inf-arg+}, then there will only be a single +@var{argument} string, which includes all inferior arguments, +separated with whitespace. + @c FIXME: What about non-stop mode? This packet is only available in extended mode (@pxref{extended mode}). @@ -44777,6 +44783,14 @@ New packets should be written to support @samp{E.@var{errtext}} regardless of this feature being true or not. + +@anchor{single-inf-arg} +@item single-inf-arg +This feature indicates that @value{GDBN} would like to send the +inferior arguments as a single string within the @samp{vRun} packet. +@value{GDBN} will not send the arguments as a single string unless the +stub also reports that is supports this behaviour by including +@samp{single-inf-arg+} in its @samp{qSupported} reply. @end table Stubs should ignore any unknown values for @@ -45075,6 +45089,11 @@ @tab @samp{+} @tab No +@item @samp{single-inf-arg} +@tab No +@tab @samp{-} +@tab No + @end multitable These are the currently defined stub features, in more detail: @@ -45321,6 +45340,12 @@ send this feature back to @value{GDBN} in the @samp{qSupported} reply, @value{GDBN} will always support @samp{E.@var{errtext}} format replies if it sent the @samp{error-message} feature. + +@item single-inf-arg +The remote stub would like to receive the inferior arguments as a +single string within the @samp{vRun} packet. The stub should only +send this feature if @value{GDBN} sent @samp{single-inf-arg+} in the +@samp{qSupported} packet. @end table @item qSymbol:: diff --git a/gdb/remote.c b/gdb/remote.c index 5a5eb5c7235..8c33ec116bd 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -399,6 +399,10 @@ enum { errors, and so they should not need to check for this feature. */ PACKET_accept_error_message, + /* Not really a packet; this indicates support for sending the vRun + inferior arguments as a single string. */ + PACKET_vRun_single_argument, + PACKET_MAX }; @@ -824,6 +828,11 @@ struct remote_features bool remote_memory_tagging_p () const { return packet_support (PACKET_memory_tagging_feature) == PACKET_ENABLE; } + /* Returns true if there is support for sending vRun inferior arguments + as a single string. */ + bool remote_vrun_single_arg_p () const + { return packet_support (PACKET_vRun_single_argument) == PACKET_ENABLE; } + /* Reset all packets back to "unknown support". Called when opening a new connection to a remote target. */ void reset_all_packet_configs_support (); @@ -5848,6 +5857,8 @@ static const struct protocol_feature remote_protocol_features[] = { PACKET_memory_tagging_feature }, { "error-message", PACKET_ENABLE, remote_supported_packet, PACKET_accept_error_message }, + { "single-inf-arg", PACKET_DISABLE, remote_supported_packet, + PACKET_vRun_single_argument }, }; static char *remote_support_xml; @@ -5959,6 +5970,10 @@ remote_target::remote_query_supported () != AUTO_BOOLEAN_FALSE) remote_query_supported_append (&q, "memory-tagging+"); + if (m_features.packet_set_cmd_state (PACKET_vRun_single_argument) + != AUTO_BOOLEAN_FALSE) + remote_query_supported_append (&q, "single-inf-arg+"); + /* Keep this one last to work around a gdbserver <= 7.10 bug in the qSupported:xmlRegisters=i386 handling. */ if (remote_support_xml != NULL @@ -10767,7 +10782,11 @@ remote_target::extended_remote_run (const std::string &args) if (!args.empty ()) { - std::vector split_args = gdb::remote_args::split (args); + std::vector split_args; + if (!m_features.remote_vrun_single_arg_p ()) + split_args = gdb::remote_args::split (args); + else + split_args.push_back (args); for (const auto &a : split_args) { @@ -16459,6 +16478,10 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL, add_packet_config_cmd (PACKET_accept_error_message, "error-message", "error-message", 0); + add_packet_config_cmd (PACKET_vRun_single_argument, + "single-inferior-argument-feature", + "single-inferior-argument-feature", 0); + /* Assert that we've registered "set remote foo-packet" commands for all packet configs. */ { diff --git a/gdb/testsuite/gdb.base/args.exp b/gdb/testsuite/gdb.base/args.exp index 363d74a1d60..8aef8cbbff9 100644 --- a/gdb/testsuite/gdb.base/args.exp +++ b/gdb/testsuite/gdb.base/args.exp @@ -72,31 +72,48 @@ proc args_test { name arglist {re_list {}} } { } } -# Test that the --args are processed correctly. +# Run all the tests. +proc run_all_tests {} { + # Test that the --args are processed correctly. -args_test basic {{1} {3}} + args_test basic {{1} {3}} -# Test that the --args are processed correctly even if one of them is -# empty. + # Test that the --args are processed correctly even if one of them is + # empty. -args_test "one empty" {{1} {} {3}} + args_test "one empty" {{1} {} {3}} -# Try with 2 empty args. + # Try with 2 empty args. -args_test "two empty" {{1} {} {} 3} + args_test "two empty" {{1} {} {} 3} -# Try with arguments containing literal single quotes. + # Try with arguments containing literal single quotes. -args_test "one empty with single quotes" {{1} {''} {3}} + args_test "one empty with single quotes" {{1} {''} {3}} -args_test "two empty with single quotes" {{1} {''} {''} {3}} + args_test "two empty with single quotes" {{1} {''} {''} {3}} -# Try with arguments containing literal newlines. + # Try with arguments containing literal newlines. -args_test "one newline" {{1} "\n" {3}} {1 \\\\n 3} + args_test "one newline" {{1} "\n" {3}} {1 \\\\n 3} -args_test "two newlines" {{1} "\n" "\n" {3}} {1 \\\\n \\\\n 3} + args_test "two newlines" {{1} "\n" "\n" {3}} {1 \\\\n \\\\n 3} -args_test "lone single quote" {{1} \' {3}} + args_test "lone single quote" {{1} \' {3}} -args_test "lone double quote" {{1} \" {3}} {1 \\\\\" 3} + args_test "lone double quote" {{1} \" {3}} {1 \\\\\" 3} +} + +run_all_tests + +# For extended-remote targets, disable the packet which passes +# inferior arguments as a single string. This changes how the vRun +# (extended-remote only) packet works. +if {[target_info gdb_protocol] == "extended-remote"} { + with_test_prefix "single-inferior-arg disabled" { + save_vars { GDBFLAGS } { + append GDBFLAGS " -ex \"set remote single-inferior-argument-feature-packet off\"" + run_all_tests + } + } +} diff --git a/gdb/testsuite/gdb.base/inferior-args.exp b/gdb/testsuite/gdb.base/inferior-args.exp index a1977dbc2e4..fc0b14cc492 100644 --- a/gdb/testsuite/gdb.base/inferior-args.exp +++ b/gdb/testsuite/gdb.base/inferior-args.exp @@ -211,14 +211,31 @@ lappend test_desc_list [list "test four" \ [list "$hex \"'\"" \ "$hex \"\\\\\"\""]] -foreach desc $test_desc_list { - lassign $desc name stub_suitable args re_list - with_test_prefix $name { - foreach_with_prefix set_method { "start" "starti" "run" "set args" } { - foreach_with_prefix startup_with_shell { on off } { - do_test $set_method $startup_with_shell $args $re_list \ - $stub_suitable +# Run all tests in the global TEST_DESC_LIST. +proc run_all_tests {} { + foreach desc $::test_desc_list { + lassign $desc name stub_suitable args re_list + with_test_prefix $name { + foreach_with_prefix set_method { "start" "starti" "run" "set args" } { + foreach_with_prefix startup_with_shell { on off } { + do_test $set_method $startup_with_shell $args $re_list \ + $stub_suitable + } } } } } + +run_all_tests + +# For extended-remote targets, disable the packet which passes +# inferior arguments as a single string. This changes how the vRun +# (extended-remote only) packet works. +if {[target_info gdb_protocol] == "extended-remote"} { + with_test_prefix "single-inferior-arg disabled" { + save_vars { GDBFLAGS } { + append GDBFLAGS " -ex \"set remote single-inferior-argument-feature-packet off\"" + run_all_tests + } + } +} diff --git a/gdb/testsuite/gdb.base/startup-with-shell.exp b/gdb/testsuite/gdb.base/startup-with-shell.exp index e27f17aeb72..0b93b7496cc 100644 --- a/gdb/testsuite/gdb.base/startup-with-shell.exp +++ b/gdb/testsuite/gdb.base/startup-with-shell.exp @@ -91,73 +91,97 @@ proc run_test_same { args re testname } { run_test $args $re $re $testname } -# The regexp to match a single '\' character. -set bs "\\\\" - -# Are we using 'remote' or 'extended-remote' protocol? -set is_remote_p [gdb_protocol_is_remote] - -## Run the actual tests - -run_test "$unique_file_dir/*.unique-extension" \ - "\"$unique_file\"" \ - "\"$unique_file_dir/\\\*\.unique-extension\"" \ - "arg is glob" \ - $is_remote_p - -run_test_same "$unique_file_dir/\\*.unique-extension" \ - "\"$unique_file_dir/\\\*\.unique-extension\"" \ - "arg is escaped glob" - -save_vars { env(TEST) } { - set env(TEST) "1234" - run_test "\$TEST" \ - "\"1234\"" \ - "\"\\\$TEST\"" \ - "arg is shell variable" \ - $is_remote_p - - run_test_same "\\\$TEST" \ - "\"\\\$TEST\"" \ - "arg is escaped shell variable" -} - -run_test_same "\"\\a\"" \ - "\"${bs}${bs}a\"" \ - "retain backslash in double quote arg" - -run_test_same "'\\a'" \ - "\"${bs}${bs}a\"" \ - "retain backslash in single quote arg" - -run_test_same "\"\\\$\"" \ - "\"\\\$\"" \ - "'\$' can be escaped in double quote arg" - -run_test_same "'\\\$'" \ - "\"${bs}${bs}\\\$\"" \ - "'\$' is not escaped in single quote arg" - -run_test_same "\"\\`\"" \ - "\"\\`\"" \ - "'`' can be escaped in double quote arg" - -run_test_same "'\\`'" \ - "\"${bs}${bs}`\"" \ - "'`' is not escaped in single quote arg" - -run_test_same "\"\\\"\"" \ - "\"${bs}\"\"" \ - "'\"' can be escaped in double quote arg" +# Run the actual tests +proc run_all_tests { { is_remote_with_split_args false } } { + # The regexp to match a single '\' character. + set bs "\\\\" + + run_test "$::unique_file_dir/*.unique-extension" \ + "\"$::unique_file\"" \ + "\"$::unique_file_dir/\\\*\.unique-extension\"" \ + "arg is glob" \ + $is_remote_with_split_args + + run_test_same "$::unique_file_dir/\\*.unique-extension" \ + "\"$::unique_file_dir/\\\*\.unique-extension\"" \ + "arg is escaped glob" + + save_vars { ::env(TEST) } { + set ::env(TEST) "1234" + run_test "\$TEST" \ + "\"1234\"" \ + "\"\\\$TEST\"" \ + "arg is shell variable" \ + $is_remote_with_split_args + + run_test_same "\\\$TEST" \ + "\"\\\$TEST\"" \ + "arg is escaped shell variable" + } -run_test_same "'\\\"'" \ - "\"${bs}${bs}${bs}\"\"" \ - "'\"' is not escaped in single quote arg" + run_test "\$(echo foo)" \ + "\"foo\"" \ + "\"\\\$\\(echo\"" \ + "arg is parameter expansion, command execution" \ + $is_remote_with_split_args + + run_test "\$((2 + 3))" \ + "\"5\"" \ + "\"\\\$\\(\\(2\"" \ + "arg is parameter expansion, expression evaluation" \ + $is_remote_with_split_args + + run_test_same "\"\\a\"" \ + "\"${bs}${bs}a\"" \ + "retain backslash in double quote arg" + + run_test_same "'\\a'" \ + "\"${bs}${bs}a\"" \ + "retain backslash in single quote arg" + + run_test_same "\"\\\$\"" \ + "\"\\\$\"" \ + "'\$' can be escaped in double quote arg" + + run_test_same "'\\\$'" \ + "\"${bs}${bs}\\\$\"" \ + "'\$' is not escaped in single quote arg" + + run_test_same "\"\\`\"" \ + "\"\\`\"" \ + "'`' can be escaped in double quote arg" + + run_test_same "'\\`'" \ + "\"${bs}${bs}`\"" \ + "'`' is not escaped in single quote arg" + + run_test_same "\"\\\"\"" \ + "\"${bs}\"\"" \ + "'\"' can be escaped in double quote arg" + + run_test_same "'\\\"'" \ + "\"${bs}${bs}${bs}\"\"" \ + "'\"' is not escaped in single quote arg" + + run_test_same "\"\\\\\"" \ + "\"${bs}${bs}\"" \ + "'\\' can be escaped in double quote arg" + + run_test_same "'\\\\'" \ + "\"${bs}${bs}${bs}${bs}\"" \ + "'\\' is not escaped in single quote arg" +} -run_test_same "\"\\\\\"" \ - "\"${bs}${bs}\"" \ - "'\\' can be escaped in double quote arg" +run_all_tests -run_test_same "'\\\\'" \ - "\"${bs}${bs}${bs}${bs}\"" \ - "'\\' is not escaped in single quote arg" +# For extended-remote targets, disable the packet which passes +# inferior arguments as a single string. This changes how the vRun +# (extended-remote only) packet works. +if {[target_info gdb_protocol] == "extended-remote"} { + with_test_prefix "single-inferior-arg disabled" { + save_vars { GDBFLAGS } { + append GDBFLAGS " -ex \"set remote single-inferior-argument-feature-packet off\"" + run_all_tests true + } + } +} diff --git a/gdbserver/server.cc b/gdbserver/server.cc index f85f52fc442..287e1ec7981 100644 --- a/gdbserver/server.cc +++ b/gdbserver/server.cc @@ -2743,6 +2743,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) } else if (feature == "error-message+") cs.error_message_supported = true; + else if (feature == "single-inf-arg+") + cs.single_inferior_argument = true; else { /* Move the unknown features all together. */ @@ -2872,6 +2874,9 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) if (target_supports_memory_tagging ()) strcat (own_buf, ";memory-tagging+"); + if (cs.single_inferior_argument) + strcat (own_buf, ";single-inf-arg+"); + /* Reinitialize components as needed for the new connection. */ hostio_handle_new_gdb_connection (); target_handle_new_gdb_connection (); @@ -3466,7 +3471,21 @@ handle_v_run (char *own_buf) else program_path.set (new_program_name.get ()); - program_args = gdb::remote_args::join (new_argv); + if (cs.single_inferior_argument) + { + if (new_argv.size () > 1) + { + write_enn (own_buf); + return; + } + else if (new_argv.size () == 1) + program_args = std::string (new_argv[0]); + else + program_args.clear (); + } + else + program_args = gdb::remote_args::join (new_argv); + free_vector_argv (new_argv); try diff --git a/gdbserver/server.h b/gdbserver/server.h index eabedb95679..f253315bd8b 100644 --- a/gdbserver/server.h +++ b/gdbserver/server.h @@ -197,6 +197,11 @@ struct client_state are not supported with qRcmd and m packets, but are still supported everywhere else. This is for backward compatibility reasons. */ bool error_message_supported = false; + + /* If true then we've agreed that the debugger will send all inferior + arguments as a single string. When false the debugger will attempt + to split the inferior arguments before sending them. */ + bool single_inferior_argument = false; }; client_state &get_client_state (); -- 2.25.4