* Support for .gdb_index sections with version less than 7 has been
removed.
+* GDB now accepts --no-escape-args as an alternative to --args on the
+ command line. GDB will not escape special shell characters within
+ arguments after --no-escape-args.
+
+* gdbserver now accepts --no-escape-args as a command line flag. When
+ this flag is used gdbserver will not escape special shell characters
+ within the inferior arguments.
+
* New targets
GNU/Linux/MicroBlaze (gdbserver) microblazeel-*linux*
``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 stop option processing.
@smallexample
@value{GDBP} --args gcc -O2 -c foo.c
@end smallexample
This will cause @code{@value{GDBP}} to debug @code{gcc}, and to set
-@code{gcc}'s command-line arguments (@pxref{Arguments}) to @samp{-O2 -c foo.c}.
+@code{gcc}'s command-line arguments (@pxref{Arguments}) to @samp{-O2
+-c foo.c}. For the differences between @code{--args} and
+@code{--no-escape-args}, see @ref{--args and --no-escape-args options,
+,@code{--args} and @code{--no-escape-args}}.
You can run @code{@value{GDBP}} without printing the front material, which describes
@value{GDBN}'s non-warranty, by specifying @code{--silent}
The annotation mechanism has largely been superseded by @sc{gdb/mi}
(@pxref{GDB/MI}).
+@anchor{--args and --no-escape-args options}
@item --args
@cindex @code{--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.
+Arguments supplied using @code{--args} will have backslashes applied
+to escape any special shell characters. This ensures that when the
+inferior starts it is passed arguments exactly as @value{GDBN}
+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 on 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".
+@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}
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
+either of these options are passed as arguments to the inferior. As
+an example, take the following command:
@smallexample
gdb ./a.out -q
@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 arguments 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},
+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}.
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
+@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
char **argv = context->argv;
static int quiet = 0;
- static int set_args = 0;
static int inhibit_home_gdbinit = 0;
+ /* Has the user passed inferior arguments on the command line. */
+ enum {
+ /* No arguments passed. */
+ NO_ARGS,
+
+ /* Arguments passed with --args. */
+ SET_ESC_ARGS,
+
+ /* Arguments passed with --no-escape-args. */
+ SET_NO_ESC_ARGS
+ } set_args = NO_ARGS;
+
/* Pointers to various arguments from command line. */
char *symarg = NULL;
char *execarg = NULL;
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. */
{"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}
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. */
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 ();
/* 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
symarg = argv[optind];
execarg = argv[optind];
++optind;
- current_inferior ()->set_args
- (gdb::array_view<char * const> (&argv[optind], argc - optind),
- startup_with_shell);
- }
+ gdb::array_view<char * const> arg_view (&argv[optind], argc - optind);
+ current_inferior ()->set_args (arg_view, (set_args == SET_ESC_ARGS));
+ }
else
{
/* OK, that's all the options. */
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\
# 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
- gdb_load $::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 $::testfile
+
+ 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 {\\\"}
+ }
+
+ # If we are starting with a shell, we're not escaping
+ # special shell characters in arguments passed to GDB,
+ # we're using a remote target, and the arguments contain
+ # a shell variable (indicated with a '$'), then this
+ # test will currently fail if we are splitting the
+ # arguments.
+ if { $startup_with_shell eq "on"
+ && $arg_flag eq "no-escape-args"
+ && [gdb_protocol_is_remote]
+ && [string first "\$" $arglist] != -1 } {
+ setup_xfail "*-*-*" gdb/28392
+ }
+
+ gdb_test "print argv\[$i\]" \
+ "\\\$$::decimal = $::hex \"$arg\"" \
+ "argv\[$i\] for $name"
+ set i [expr $i + 1]
+ }
}
}
}
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}}
+}
--- /dev/null
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2023-2025 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/>. */
+
+#include <stdio.h>
+
+int
+main (int argc, char **argv)
+{
+ for (int i = 0; i < argc; i++)
+ printf ("[%d] %s\n", i, argv[i]);
+
+ return 0;
+}
--- /dev/null
+# Copyright 2023-2025 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/>.
+
+# 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 ${::testfile}
+
+ 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 {
+ 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}
+}
" --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"
volatile bool multi_mode = false;
volatile bool attach = false;
bool selftest = false;
+ bool escape_args = true;
#if GDB_SELF_TEST
std::vector<const char *> selftest_filters;
OPT_DEBUG, OPT_DEBUG_FILE, OPT_DEBUG_FORMAT, OPT_DISABLE_PACKET,
OPT_DISABLE_RANDOMIZATION, OPT_NO_DISABLE_RANDOMIZATION,
OPT_STARTUP_WITH_SHELL, OPT_NO_STARTUP_WITH_SHELL, OPT_ONCE,
- OPT_SELFTEST,
+ OPT_SELFTEST, OPT_NO_ESCAPE
};
static struct option longopts[] =
OPT_NO_STARTUP_WITH_SHELL},
{"once", no_argument, nullptr, OPT_ONCE},
{"selftest", optional_argument, nullptr, OPT_SELFTEST},
+ {"no-escape-args", no_argument, nullptr, OPT_NO_ESCAPE},
{nullptr, no_argument, nullptr, 0}
};
}
break;
+ case OPT_NO_ESCAPE:
+ escape_args = false;
+ break;
+
case '?':
/* Figuring out which element of ARGV contained the invalid
argument is not simple. There are a couple of cases we need
int n = argc - (next_arg - argv);
program_args
- = construct_inferior_arguments ({&next_arg[1], &next_arg[n]}, true);
+ = construct_inferior_arguments ({&next_arg[1], &next_arg[n]},
+ escape_args);
/* Wait till we are at first instruction in program. */
target_create_inferior (program_path.get (), program_args);