Files
binutils-gdb/gdb/testsuite/gdb.base/args.exp
Michael Weghorn 0df62bf09e gdb: Support some escaping of args with startup-with-shell being off
I (Andrew Burgess) have taken this patch from this series:

  https://inbox.sourceware.org/gdb-patches/20211022071933.3478427-1-m.weghorn@posteo.de/

I started off reviewing that series, but wanted to explore some
alternative strategies for solving the problems this series addresses.
However, this patch I think is super useful, so I've taken it mostly
as it was in the original series.

I have made a few minor cleanups, and I've also added some more tests.
Any bugs should be considered mine (Andrew's), but I've left the
original author (Michael Weghorn) in place as the GDB side changes are
mostly their work.

The function execv_argv::init_for_no_shell (gdb/nat/fork-inferior.c),
is passed a single string ALLARGS containing all of the inferior
arguments, and contains some custom code for splitting this argument
string into a vector of separate arguments.  This function is used
when startup-with-shell is off (which is not the default).

The algorithm in this function was just splitting on whitespace
characters, and ignoring any quoting, so for example:

    (gdb) set startup-with-shell off
    (gdb) set args "first arg" second_arg

would result in three arguments ("first), (arg"), and (second_arg)
being passed to the inferior (the parenthesis are not part of the
parsed arguments).

This commit replaces this custom argument splitting with a use of the
existing gdb_argv class (which uses the libiberty buildargv function).
This does a better job of supporting quoting and escaping, so for the
example given above we now pass two arguments (first arg)
and (second_arg), which is certainly what I would have expected as a
GDB user.

This commit changes the 'execv_argv' class accordingly and drops the
optimization to have all the 'char *' in 'm_argv' point to a single
string rather than allocating a separate string for each arg.  This is
needed because we are now going to be stripping some escaping from the
arguments, for example:

    (gdb) set startup-with-shell off
    (gdb) set args "literal \$"

In this case we will pass the single argument (literal $) to the
inferior, the escaping backslash will be removed.  This might seem
strange as usually the backslash would be stripped by the shell, and
now we have no shell.  However, I think the consistent behaviour is a
good thing; whether we start with a shell or not the escaping will be
removed.

Using gdb_argv will mean that quote characters are also stripped.  If
we consider the first example again:

    (gdb) set startup-with-shell off
    (gdb) set args "first arg" second_arg

This is now going to pass (first arg) and (second_arg), the quotes
have been removed.  If the user did want the original behaviour then
they are going to have to now do this:

    (gdb) set startup-with-shell off
    (gdb) set args \"first arg\" second_arg

or they could do this:

    (gdb) set startup-with-shell off
    (gdb) set args '"first' 'arg"' second_arg

This commit also extends the three tests that cover inferior argument
passing to cover the case where 'startup-with-shell' is off.  All of
these new tests pass for native targets, but there are still problems
when using remote targets.

The remote target problems arise because of how escaping is handled
while passing arguments to remote targets.  I have a larger series
that aims to address this issue:

  https://inbox.sourceware.org/gdb-patches/cover.1730731085.git.aburgess@redhat.com

This patch was originally part of that series, but getting a 14 patch
series reviewed is not easy, so I've pulled this patch out on its own
for now, and the new tests are (rather crudely) disabled for remote
targets.

My hope is to work through my 14 patch series posting all of the
patches in smaller groups, which will hopefully make reviewing
easier.  As more of that series gets merged, the remote argument
handling will improve, before, eventually, no tests will need to be
disabled.

Co-Authored-By: Andrew Burgess <aburgess@redhat.com>
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=28392

Tested-By: Guinevere Larsen <guinevere@redhat.com>
Reviewed-By: Keith Seitz <keiths@redhat.com>
2025-02-09 16:06:53 +00:00

112 lines
3.4 KiB
Plaintext

# Copyright 2003-2024 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 <http://www.gnu.org/licenses/>.
# This is a test for the gdb invocation option --args.
# Skip test if target does not support argument passing.
require {!target_info exists noargs}
# This test requires starting new inferior processes, skip it if the target
# board is a stub.
require !use_gdb_stub
standard_testfile
if {[build_executable $testfile.exp $testfile $srcfile] == -1} {
untested "failed to compile"
return -1
}
set startup_with_shell_modes { "on" }
if {![gdb_protocol_is_remote]} {
lappend startup_with_shell_modes "off"
} else {
# Some of these tests will not work when using the remote protocol
# due to bug PR gdb/28392.
unsupported "gdbserver 'startup-with-shell off' broken PR gdb/28392"
}
# 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
}
foreach_with_prefix startup_with_shell $::startup_with_shell_modes {
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"
set i 1
foreach arg $re_list {
gdb_test "print argv\[$i\]" "\\\$$::decimal = $::hex \"$arg\"" \
"argv\[$i\] for $name"
set i [expr $i + 1]
}
}
}
}
# Test that the --args are processed correctly.
args_test basic {{1} {3}}
# Test that the --args are processed correctly even if one of them is
# empty.
args_test "one empty" {{1} {} {3}}
# Try with 2 empty args.
args_test "two empty" {{1} {} {} 3}
# Try with arguments containing literal single quotes.
args_test "one empty with single quotes" {{1} {''} {3}}
args_test "two empty with single quotes" {{1} {''} {''} {3}}
# Try with arguments containing literal newlines.
args_test "one newline" {{1} "\n" {3}} {1 \\\\n 3}
args_test "two newlines" {{1} "\n" "\n" {3}} {1 \\\\n \\\\n 3}
args_test "lone single quote" {{1} \' {3}}
args_test "lone double quote" {{1} \" {3}} {1 \\\\\" 3}