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.133.124]) by sourceware.org (Postfix) with ESMTPS id D327B3858283 for ; Sun, 21 Jan 2024 03:57:17 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org D327B3858283 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 D327B3858283 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=1705809441; cv=none; b=ISFOqWkhfqUrf4ecs7nTe1S8cP5AZPj95MMR3m4JUx8u2YwLTRfi7DtbHQUTyinSaGNU5b/6CiIRyoqFTAlJ6Cr8csi2MEHsEvxO2Cpb64TnxoVVBEU146YcroYTshztmg6KqNr5gfcKWApUhlveU8zbm9OrjIZsOViQ5B/VnD4= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1705809441; c=relaxed/simple; bh=6pLHYOL/1AKahC3F14m1hcxtbJqQLUUTCQ/9W0br4is=; h=DKIM-Signature:Message-ID:Date:MIME-Version:Subject:To:From; b=Ah2OLIdpu9Zn8YjjqnLDNfD1niRtU4XLpRya6FUWz+Lj3mGKUsn/0RJ9HAhioS7QAr4+s9LrwoeRa4lCngr2AheW4UrQoFC5JhNfLJxioAZG8Iod0fdoNl/X9uEgs3Nz5AW8M+IHj33GXnaitaSyoOXYF33BE+uFPZUtb8WEMEw= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1705809437; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=s/3cY30my4OhJT3sCQLUk/+ZPlPvKuR6qsRTiPFh7NA=; b=YUXSB3SGJC/hj/GH5Crc/S6E/LbRt/QRlQQcK2Om/0FqExgvIDt7238d9nlaRLlALpCSi/ 8Wxkz4h2qfONLDOs52mwpbDGdIjpRtOBfs1RgEI9iZW7qLtSKpuxhvDp8DtEeAjugmzMNv IB8w7Y7YkjzmKeDQyRWifkjYjyazhw0= Received: from mail-qk1-f200.google.com (mail-qk1-f200.google.com [209.85.222.200]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-664-FIgD3v2oOvu5syd5swoLkw-1; Sat, 20 Jan 2024 22:57:16 -0500 X-MC-Unique: FIgD3v2oOvu5syd5swoLkw-1 Received: by mail-qk1-f200.google.com with SMTP id af79cd13be357-783603ba574so351219185a.2 for ; Sat, 20 Jan 2024 19:57:16 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1705809435; x=1706414235; h=content-transfer-encoding:in-reply-to:from:references:to :content-language:subject:user-agent:mime-version:date:message-id :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=s/3cY30my4OhJT3sCQLUk/+ZPlPvKuR6qsRTiPFh7NA=; b=tU/1phJr00qdaMblv+EbIOUXb9vc/70sDPMJNkSn3A5bNwZysevWkXF/knxS4B6H5n VdWj33AJaYmUTezh+am/xsxyp9HIQgE7dr1go9SUlZV6MKNamIeflZv4tna9riRBgHHW 8DkhQb2odM8drDwNwt0mZvsf9b6kSmAFDhI8Q3j4s77V7jHoNUHnkdldpVObnz1eJ83Z 1Tahi5jKACgg5jkmAuSKvRwbWmmFmX9qP0/fAaDBEw3yjnkraoxmC+cx/wg5NVLu1FVz 2ZPgb3RmUHaarlBoXMo5CjGyfqgoJmIi2bIRXa1M5OenJ0bHk1N4RMg2SO7rqs1mqYWy uIBQ== X-Gm-Message-State: AOJu0YzsHsqEAuiQ3R1DNFf6HniqWjm9A6IUCrQu1tvf8nGNchYK8tXF PivBiKWs1hnZn4rK9hKatjrQwTN3U0ER3EBmPk+nSzQYiNBm3sNXianIMOwl7k47A7EIut8F1ne yglzgIhL8Y/U/4xlscn72q8Fh6g3EsDIkHURR6+6wWRKScsrFe0c8bswlCZsGIHqNitA= X-Received: by 2002:ae9:f013:0:b0:783:4da7:cb0a with SMTP id l19-20020ae9f013000000b007834da7cb0amr2554869qkg.133.1705809435223; Sat, 20 Jan 2024 19:57:15 -0800 (PST) X-Google-Smtp-Source: AGHT+IFFH00n/qXbLEDwNH3WmI5oVTtRxvOMjkxweBxls10UPbA9tBR2pLG+lJxOLxwMmAsxQW44JQ== X-Received: by 2002:ae9:f013:0:b0:783:4da7:cb0a with SMTP id l19-20020ae9f013000000b007834da7cb0amr2554859qkg.133.1705809434455; Sat, 20 Jan 2024 19:57:14 -0800 (PST) Received: from [150.1.200.12] (174-21-92-140.tukw.qwest.net. [174.21.92.140]) by smtp.gmail.com with ESMTPSA id db11-20020a17090ad64b00b002900eeada1asm6834134pjb.43.2024.01.20.19.57.13 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 20 Jan 2024 19:57:14 -0800 (PST) Message-ID: <28c25e2d-4f33-49ba-9c3e-3b82c192ca93@redhat.com> Date: Sat, 20 Jan 2024 19:57:13 -0800 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [PATCH 12/16] gdb/gdbserver: add a '--no-escape-args' command line option To: Andrew Burgess , gdb-patches@sourceware.org References: <47fe194ee2e88d8ed68192abc31ac8e3df626fe1.1704809585.git.aburgess@redhat.com> From: Keith Seitz In-Reply-To: <47fe194ee2e88d8ed68192abc31ac8e3df626fe1.1704809585.git.aburgess@redhat.com> X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Language: en-US Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Spam-Status: No, score=-12.4 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,KAM_SHORT,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL,SPF_HELO_NONE,SPF_NONE,TXREP,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: [I realize the documentation has already been approved. Nonetheles, I noticed some typos.] On 1/9/24 06:26, Andrew Burgess wrote: > diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo > index 9dbe53384e1..abb07d74baf 100644 > --- a/gdb/doc/gdb.texinfo > +++ b/gdb/doc/gdb.texinfo > @@ -898,9 +898,9 @@ > ``process'', and there is often no way to get a core dump. @value{GDBN} > will warn you if it is unable to attach or to read core dumps. > > -You can optionally have @code{@value{GDBP}} pass any arguments after the > -executable file to the inferior using @code{--args}. This option stops > -option processing. > +You can optionally have @code{@value{GDBP}} pass any arguments after > +the executable file to the inferior using @code{--args} or > +@code{--no-escape-args}. These options stops option processing. > @smallexample > @value{GDBP} --args gcc -O2 -c foo.c > @end smallexample > @@ -1246,6 +1246,56 @@ > executable file are passed as command line arguments to the inferior. > This option stops option processing. > > +Argument supplied using @code{--args} will have backslashes applied to I think this should be "Arguments". > +escape any special shell characters. This ensures that when the > +inferior starts it is passed arguments exactly as @value{GDBN} and a comma is needed after the introductory phrase, "when the inferior starts." > +receives them. > + > +For example, consider the following command run under a shell: > +@smallexample > +@value{GDBP} --args ls *.c > +@end smallexample > +@noindent > +In this case the shell will expand @kbd{*.c} at the time @value{GDBN} > +is invoked, not at the time that the inferior is invoked. As a > +result, if an additional @kbd{.c} file is created after @value{GDBN} > +is started, but before the inferior is started, then the inferior will > +not show the file in its output; the list of matching files was > +resolved at the time @value{GDBN} was started. > + > +If you quote the @kbd{*} character used in the @value{GDBN} command > +line argument then this will prevent the shell that starts > +@value{GDBN} from expanding the @kbd{*.c} pattern, however, this > +quoting will also be passed to the shell that @value{GDBN} invokes in > +order to start the inferior (@pxref{set startup-with-shell}), and this > +will prevent the @kbd{*.c} pattern being expanded at this point either: > +@smallexample > +@value{GDBP} --args ls '*.c' > +(@value{GDBP}) show args > +Argument list to give program being debugged when it is started is "\*.log". Is this supposed to be "\*.c"? > +@end smallexample > +@noindent > +If this quoting behaviour does not meet your needs, then you could use > +@code{--no-escape-args} instead, which is described below. > + > +@item --no-escape-args > +@cindex @code{--no-escape-args} > +Change interpretation of command line so that arguments following the > +executable file are passed as command line arguments to the inferior. > +This option stops option processing. > + > +Unlike @code{--args}, arguments after the executable name will not > +have any escaping applied to them. As a result, any special shell > +characters that are not expanded by the shell that invokes > +@value{GDBN} will be expanded by the shell that @value{GDBN} uses to > +start the inferior. > + > +@smallexample > +@value{GDBP} --no-escape-args ls '*.c' > +(@value{GDBP}) show args > +Argument list to give program being debugged when it is started is "*.log". > +@end smallexample > + > @item -baud @var{bps} > @itemx -b @var{bps} > @cindex @code{--baud} > @@ -50498,9 +50548,10 @@ > directly to @code{stdout}, will also be made silent. > > @item --args @var{prog} [@var{arglist}] > -Change interpretation of command line so that arguments following this > -option are passed as arguments to the inferior. As an example, take > -the following command: > +@itemx --no-escape-args @var{prog} [@var{arglist}] > +Change interpretation of command line so that arguments following "Change the"? > +either of these options are passed as arguments to the inferior. As > +an example, take the following command: > > @smallexample > gdb ./a.out -q > @@ -50515,7 +50566,44 @@ > @end smallexample > > @noindent > -starts @value{GDBN} with the introductory message, and passes the option to the inferior. > +starts @value{GDBN} with the introductory message, and passes the > +option @code{-q} to the inferior. > + > +The difference between @option{--args} and @option{--no-escape-args} > +is whether @value{GDBN} applies escapes to the argument it sees: > + > +@smallexample > +gdb --args ./a.out *.c > +@end smallexample > + > +@noindent > +in this case the @code{*.c} is expanded by the shell that invokes > +@value{GDBN}, the list of matching files will be fixed in the inferior > +argument list. If instead this is used: > + > +@smallexample > +gdb --args ./a.out '*.c' > +@end smallexample > + > +@noindent > +then the shell that invokes @value{GDBN} will not expand @code{*.c}, > +but instead @value{GDBN} will escape the @code{*} character so when > +a.out is invoked it will be passed a literal @code{*.c}. If instead > +this is used: > + > +@smallexample > +gdb --no-escape-args ./a.out '*.c' > +@end smallexample > + > +@noindent > +now @value{GDBN} will not escape the @code{*} character. When the > +inferior is invoked the @code{*.c} will be expanded, and the inferior > +will be passed the list of files as present at the time the inferior > +is invoked. > + > +This change of behaviour can be important if the list of matching > +files could change between the time that @value{GDBN} is started, and > +the time the inferior is started. > > @item --pid=@var{pid} > Attach @value{GDBN} to an already running program, with the PID @var{pid}. > @@ -50857,6 +50945,18 @@ > with the @option{--once} option, it will stop listening for any further > connection attempts after connecting to the first @value{GDBN} session. > > +@item --no-escape-args > +By default, inferior arguments passed on the @command{gdbserver} > +command line will have any special shell characters escaped by > +@command{gdbserver}. This ensures that when @command{gdbserver} > +invokes the inferior, the arguments passed to the inferior are > +identical to the arguments passed to @command{gdbserver}. > + > +To disable this escaping, use @option{--no-escape-args}. With this > +option special shell characters will not be escaped. When Need a comma between "option" and "special." Keith > +@command{gdbserver} starts a new shell in order to invoke the > +inferior, this new shell will expand any special shell characters. > + > @c --disable-packet is not documented for users. > > @c --disable-randomization and --no-disable-randomization are superseded by > diff --git a/gdb/main.c b/gdb/main.c > index 015ed396f58..e9cd4172e4a 100644 > --- a/gdb/main.c > +++ b/gdb/main.c > @@ -622,9 +622,10 @@ captured_main_1 (struct captured_main_args *context) > char **argv = context->argv; > > static int quiet = 0; > - static int set_args = 0; > static int inhibit_home_gdbinit = 0; > > + enum { NO_ARGS, SET_ESC_ARGS, SET_NO_ESC_ARGS } set_args = NO_ARGS; > + > /* Pointers to various arguments from command line. */ > char *symarg = NULL; > char *execarg = NULL; > @@ -773,7 +774,9 @@ captured_main_1 (struct captured_main_args *context) > OPT_EIX, > OPT_EIEX, > OPT_READNOW, > - OPT_READNEVER > + OPT_READNEVER, > + OPT_SET_ESC_ARGS, > + OPT_SET_NO_ESC_ARGS, > }; > /* This struct requires int* in the struct, but write_files is a bool. > So use this temporary int that we write back after argument parsing. */ > @@ -846,7 +849,8 @@ captured_main_1 (struct captured_main_args *context) > {"windows", no_argument, NULL, OPT_WINDOWS}, > {"statistics", no_argument, 0, OPT_STATISTICS}, > {"write", no_argument, &write_files_1, 1}, > - {"args", no_argument, &set_args, 1}, > + {"args", no_argument, nullptr, OPT_SET_ESC_ARGS}, > + {"no-escape-args", no_argument, nullptr, OPT_SET_NO_ESC_ARGS}, > {"l", required_argument, 0, 'l'}, > {"return-child-result", no_argument, &return_child_result, 1}, > {0, no_argument, 0, 0} > @@ -858,7 +862,7 @@ captured_main_1 (struct captured_main_args *context) > > c = getopt_long_only (argc, argv, "", > long_options, &option_index); > - if (c == EOF || set_args) > + if (c == EOF || set_args != NO_ARGS) > break; > > /* Long option that takes an argument. */ > @@ -939,6 +943,12 @@ captured_main_1 (struct captured_main_args *context) > case OPT_EIEX: > cmdarg_vec.emplace_back (CMDARG_EARLYINIT_COMMAND, optarg); > break; > + case OPT_SET_ESC_ARGS: > + set_args = SET_ESC_ARGS; > + break; > + case OPT_SET_NO_ESC_ARGS: > + set_args = SET_NO_ESC_ARGS; > + break; > case 'B': > batch_flag = batch_silent = 1; > gdb_stdout = new null_file (); > @@ -1072,7 +1082,7 @@ captured_main_1 (struct captured_main_args *context) > > /* Now that gdb_init has created the initial inferior, we're in > position to set args for that inferior. */ > - if (set_args) > + if (set_args != NO_ARGS) > { > /* The remaining options are the command-line options for the > inferior. The first one is the sym/exec file, and the rest > @@ -1084,8 +1094,11 @@ captured_main_1 (struct captured_main_args *context) > symarg = argv[optind]; > execarg = argv[optind]; > ++optind; > + escape_args_func escape_func > + = ((set_args == SET_ESC_ARGS) ? escape_shell_characters > + : escape_quotes_and_white_space); > gdb::array_view arg_view (&argv[optind], argc - optind); > - current_inferior ()->set_args (arg_view, escape_shell_characters); > + current_inferior ()->set_args (arg_view, escape_func); > } > else > { > @@ -1398,7 +1411,8 @@ This is the GNU debugger. Usage:\n\n\ > gdb_puts (_("\ > Selection of debuggee and its files:\n\n\ > --args Arguments after executable-file are passed to inferior.\n\ > - --core=COREFILE Analyze the core dump COREFILE.\n\ > + --no-escape-args Like --args, but arguments are not escaped.\n \ > + --core=COREFILE Analyze the core dump COREFILE.\n \ > --exec=EXECFILE Use EXECFILE as the executable.\n\ > --pid=PID Attach to running process PID.\n\ > --directory=DIR Search for source files in DIR.\n\ > diff --git a/gdb/testsuite/gdb.base/args.exp b/gdb/testsuite/gdb.base/args.exp > index 7c123e36404..9ff9e7ee6d1 100644 > --- a/gdb/testsuite/gdb.base/args.exp > +++ b/gdb/testsuite/gdb.base/args.exp > @@ -32,41 +32,73 @@ if {[build_executable $testfile.exp $testfile $srcfile] == -1} { > # NAME is the name to use for the tests and ARGLIST is the list of > # arguments that are passed to GDB when it is started. > # > -# The optional RE_LIST is the list of patterns to check the arguments > -# against, these patterns should match ARGLIST. If the arguments are > -# expected to show up unmodified in the test output then RE_LIST can > -# be dropped, and this proc will reuse ARGLIST. > - > -proc args_test { name arglist {re_list {}} } { > - > - # If RE_LIST is not supplied then we can reuse ARGLIST, this > - # implies that the arguments will appear unmodified in the test > - # output. > - if {[llength $re_list] == 0} { > - set re_list $arglist > +# The optional RE_ESC_LIST is the list of patterns to check the > +# inferior arguments against when GDB is started using --args. If > +# RE_ESC_LIST is not given then ARGLIST is reused, this implies that > +# the inferior arguments appear unchanged in the test output. > +# > +# The optional RE_NO_ESC_LIST is the list of patterns to check the > +# inferior arguments against when GDB is started using > +# --no-escape-args. If RE_NO_ESC_LIST is not given then RE_ESC_LIST > +# is reused, this implies that there's no difference between the test > +# output when the arguments are escaped or not. > + > +proc args_test { name arglist {re_esc_list {}} {re_no_esc_list {}} } { > + > + # If either of the two regexp lists are not specificed then we can > + # use an earlier argument value instead. > + # > + # For the first regexp list, if this is missing then we use the > + # argument list, this assumes that the arguments will appear > + # unmodified in the output. > + if {[llength $re_esc_list] == 0} { > + set re_esc_list $arglist > } > > - foreach_with_prefix startup_with_shell { on off } { > - save_vars { ::GDBFLAGS } { > - set ::GDBFLAGS "$::GDBFLAGS --args $::binfile $arglist" > - > - clean_restart $::binfile > - > - gdb_test_no_output "set startup-with-shell ${startup_with_shell}" \ > - "set startup-with-shell for $name" > - > - runto_main > - gdb_breakpoint [gdb_get_line_number "set breakpoint here"] > - gdb_continue_to_breakpoint "breakpoint for $name" > - > - set expected_len [expr 1 + [llength $re_list]] > - gdb_test "print argc" "\\\$$::decimal = $expected_len" "argc for $name" > + # If the second regexp list is missing then we reuse the first > + # regexp list. This assumes there's no difference between escaped > + # and unescaped arguments in the output. > + if {[llength $re_no_esc_list] == 0} { > + set re_no_esc_list $re_esc_list > + } > > - set i 1 > - foreach arg $re_list { > - gdb_test "print argv\[$i\]" "\\\$$::decimal = $::hex \"$arg\"" \ > - "argv\[$i\] for $name" > - set i [expr $i + 1] > + foreach_with_prefix startup_with_shell { on off } { > + foreach_with_prefix arg_flag { args no-escape-args } { > + save_vars { ::GDBFLAGS } { > + set ::GDBFLAGS "$::GDBFLAGS --${arg_flag} $::binfile $arglist" > + > + clean_restart $::binfile > + > + gdb_test_no_output \ > + "set startup-with-shell ${startup_with_shell}" \ > + "set startup-with-shell for $name" > + > + runto_main > + gdb_breakpoint [gdb_get_line_number "set breakpoint here"] > + gdb_continue_to_breakpoint "breakpoint for $name" > + > + if { $arg_flag eq "args" || $startup_with_shell eq "off" } { > + set re_list $re_esc_list > + } else { > + set re_list $re_no_esc_list > + } > + > + set expected_len [expr 1 + [llength $re_list]] > + gdb_test "print argc" \ > + "\\\$$::decimal = $expected_len" "argc for $name" > + > + set i 1 > + foreach arg $re_list { > + if { $arg eq "\n" } { > + set arg {\\n} > + } elseif { $arg eq "\"" } { > + set arg {\\\"} > + } > + gdb_test "print argv\[$i\]" \ > + "\\\$$::decimal = $::hex \"$arg\"" \ > + "argv\[$i\] for $name" > + set i [expr $i + 1] > + } > } > } > } > @@ -102,6 +134,11 @@ proc run_all_tests {} { > args_test "lone single quote" {{1} \' {3}} > > args_test "lone double quote" {{1} \" {3}} {1 \\\\\" 3} > + > + save_vars { ::env(TEST) } { > + set ::env(TEST) "ABCD" > + args_test "shell variable" {{$TEST}} {\\$TEST} {{ABCD}} > + } > } > > run_all_tests > diff --git a/gdb/testsuite/gdb.server/inferior-args.c b/gdb/testsuite/gdb.server/inferior-args.c > new file mode 100644 > index 00000000000..5fd215f50a8 > --- /dev/null > +++ b/gdb/testsuite/gdb.server/inferior-args.c > @@ -0,0 +1,27 @@ > +/* This testcase is part of GDB, the GNU debugger. > + > + Copyright 2023 Free Software Foundation, Inc. > + > + This program is free software; you can redistribute it and/or modify > + it under the terms of the GNU General Public License as published by > + the Free Software Foundation; either version 3 of the License, or > + (at your option) any later version. > + > + This program is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + GNU General Public License for more details. > + > + You should have received a copy of the GNU General Public License > + along with this program. If not, see . */ > + > +#include > + > +int > +main (int argc, char **argv) > +{ > + for (int i = 0; i < argc; i++) > + printf ("[%d] %s\n", i, argv[i]); > + > + return 0; > +} > diff --git a/gdb/testsuite/gdb.server/inferior-args.exp b/gdb/testsuite/gdb.server/inferior-args.exp > new file mode 100644 > index 00000000000..9b2aeb249e0 > --- /dev/null > +++ b/gdb/testsuite/gdb.server/inferior-args.exp > @@ -0,0 +1,157 @@ > +# Copyright 2023 Free Software Foundation, Inc. > + > +# This program is free software; you can redistribute it and/or modify > +# it under the terms of the GNU General Public License as published by > +# the Free Software Foundation; either version 3 of the License, or > +# (at your option) any later version. > +# > +# This program is distributed in the hope that it will be useful, > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > +# GNU General Public License for more details. > +# > +# You should have received a copy of the GNU General Public License > +# along with this program. If not, see . > + > +# Test passing inferior arguments on the gdbserver command line. Tests the > +# flags --no-startup-with-shell and --no-escape-args that change how GDB > +# interprets the arguments being passed. > + > +# This test relies on starting gdbserver using the pipe syntax. Not sure > +# how well this will run if part of this test is being run elsewhere. > +require {!is_remote target} {!is_remote host} > + > +load_lib gdbserver-support.exp > + > +standard_testfile > + > +require allow_gdbserver_tests > + > +set gdbserver [find_gdbserver] > +if { $gdbserver == "" } { > + unsupported "could not find gdbserver" > + return > +} > + > +standard_testfile > +if {[build_executable "failed to prepare" $testfile $srcfile]} { > + return -1 > +} > + > +# EXTENDED_P is a boolean, when true gdbserver is started with --multi, and > +# GDB connects using extended-remote protocol. Otherwise, no --multi flag > +# is passed, and GDB connects with the remote protocol. > +# > +# WITH_SHELL_P is a boolean, when true gdbserver starts the inferior using a > +# shell, when false gdbserver is passed the --no-startup-with-shell command > +# line option, and should not start the inferior through a shell. > +# > +# ESCAPE_P is a boolean, when true gdbserver applies escapes to the inferior > +# arguments, when false gdbserver is passed the --no-escape-args command > +# line option, and should not apply escaping to the inferior arguments. > +# > +# ARGLIST is a list of inferior arguments to add to the gdbserver command > +# line. > +# > +# RE_LIST is a list of patterns to match, one for each of ARGLIST. Once the > +# inferior is started we check that each argument matches its corresponding > +# entry in RE_LIST. > +proc do_test_inner { extended_p with_shell_p escape_p arglist re_list } { > + > + clean_restart ${::binfile} > + > + gdb_test_no_output "set sysroot" > + > + # Make sure we're disconnected, in case we're testing with an > + # extended-remote board, therefore already connected. > + gdb_test "disconnect" ".*" > + > + if { $extended_p } { > + set protocol "extended-remote" > + } else { > + set protocol "remote" > + } > + > + if { $escape_p } { > + set esc_opt "" > + } else { > + set esc_opt "--no-escape-args" > + } > + > + if { $with_shell_p } { > + set shell_opt "" > + } else { > + set shell_opt "--no-startup-with-shell" > + } > + > + gdb_test "target ${protocol} | ${::gdbserver} --once ${esc_opt} ${shell_opt} - ${::binfile} ${arglist}" \ > + ".*" \ > + "start gdbserver over stdin" > + > + gdb_breakpoint main > + gdb_continue_to_breakpoint main > + > + set expected_len [expr 1 + [llength $re_list]] > + gdb_test "print argc" \ > + "\\\$$::decimal = $expected_len" "check argc" > + > + set i 1 > + foreach arg $re_list { > + verbose -log "APB ($arg)" > + gdb_test "print argv\[$i\]" \ > + "\\\$$::decimal = $::hex \"$arg\"" \ > + "check argv\[$i\]" > + set i [expr $i + 1] > + } > +} > + > +# Wrapper around do_test_inner. NAME is the name of this test, used to make > +# the test names unique. ARGLIST is the list of inferior arguments to add > +# to the gdbserver command line. > +# > +# The optional RE_ESC_LIST is a list of patterns to match against the > +# inferior arguments once the inferior is started, one pattern for each > +# argument. If RE_ESC_LIST is not given then ARGLIST is reused, which > +# implies the arguments appear unmodified in the test output. > +# > +# The optional RE_NO_ESC_LIST is a list of patterns ot match against the > +# inferior arguments when gdbserver is started with --no-escape-args or > +# --no-startup-with-shell. There should be one pattern for each argument. > +# If RE_NO_ESC_LIST is not given then RE_ESC_LIST is resused, which implies > +# there's no difference in how the arguments are printed. > +proc args_test { name arglist {re_esc_list {}} {re_no_esc_list {}} } { > + if {[llength $re_esc_list] == 0} { > + set re_esc_list $arglist > + } > + > + if {[llength $re_no_esc_list] == 0} { > + set re_no_esc_list $re_esc_list > + } > + > + foreach_with_prefix extended_p { yes no } { > + foreach_with_prefix startup_with_shell { on off } { > + foreach_with_prefix escape_p { yes no } { > + if { $escape_p || !$startup_with_shell } { > + set re_list $re_esc_list > + } else { > + set re_list $re_no_esc_list > + } > + > + with_test_prefix "$name" { > + do_test_inner $extended_p $startup_with_shell \ > + $escape_p $arglist $re_list > + } > + } > + } > + } > +} > + > +args_test "basic" {a b c} > +args_test "one empty" {1 "" 3} > +args_test "two empty" {1 "" "" 3} > +args_test "one with single quotes" {1 "''" 3} > +args_test "lone double quote" {"1" \" 3} {1 \\\\\" 3} > +save_vars { env(TEST) } { > + set env(TEST) "ABCD" > + args_test "shell variable" {\$TEST} {\\$TEST} {ABCD} > +} > diff --git a/gdbserver/server.cc b/gdbserver/server.cc > index 65df03ef309..0445fa0237f 100644 > --- a/gdbserver/server.cc > +++ b/gdbserver/server.cc > @@ -3837,10 +3837,20 @@ gdbserver_usage (FILE *stream) > " --startup-with-shell\n" > " Start PROG using a shell. I.e., execs a shell that\n" > " then execs PROG. (default)\n" > + " To make use of globbing and variable subsitution for\n" > + " arguments passed directly on gdbserver invocation,\n" > + " see the --no-escape-args command line option in\n" > + " addition\n" > " --no-startup-with-shell\n" > " Exec PROG directly instead of using a shell.\n" > - " Disables argument globbing and variable substitution\n" > - " on UNIX-like systems.\n" > + " --no-escape-args\n" > + " If PROG is started using a shell (see the\n" > + " --[no-]startup-with-shell option),\n" > + " ARGS passed directly on gdbserver invocation are\n" > + " escaped, so no globbing or variable substitution\n" > + " happens for those. This option disables escaping, so\n" > + " globbing and variable substituation in the shell\n" > + " are done for ARGS on UNIX-like systems.\n" > "\n" > "Debug options:\n" > "\n" > @@ -4074,6 +4084,7 @@ captured_main (int argc, char *argv[]) > volatile int attach = 0; > int was_running; > bool selftest = false; > + bool escape_args = true; > #if GDB_SELF_TEST > std::vector selftest_filters; > > @@ -4230,6 +4241,8 @@ captured_main (int argc, char *argv[]) > startup_with_shell = true; > else if (strcmp (*next_arg, "--no-startup-with-shell") == 0) > startup_with_shell = false; > + else if (strcmp (*next_arg, "--no-escape-args") == 0) > + escape_args = false; > else if (strcmp (*next_arg, "--once") == 0) > run_once = true; > else if (strcmp (*next_arg, "--selftest") == 0) > @@ -4339,8 +4352,10 @@ captured_main (int argc, char *argv[]) > std::vector temp_arg_vector; > for (i = 1; i < n; i++) > temp_arg_vector.push_back (next_arg[i]); > + escape_args_func escape_func = (escape_args ? escape_shell_characters > + : escape_quotes_and_white_space); > program_args = construct_inferior_arguments (temp_arg_vector, > - escape_shell_characters); > + escape_func); > > /* Wait till we are at first instruction in program. */ > target_create_inferior (program_path.get (), program_args);