mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-11-16 04:24:43 +00:00
gdb: split up construct_inferior_arguments
The function construct_inferior_arguments (gdbsupport/common-inferior.cc) currently escapes all special shell characters. After this commit there will be two "levels" of quoting: 1. The current "full" quoting, where all posix shell special characters are quoted, and 2. a new "reduced" quoting, where only the characters that GDB sees as special (quotes and whitespace) are quoted. After this, almost all construct_inferior_arguments calls will use the "full" quoting, which is the current quoting. The "reduced" quoting will be used in this commit to restore the behaviour that was lost in the previous commit (more details below). In the future, the reduced quoting will be useful for some additional inferior argument that I have planned. I already posted my full inferior argument work here: https://inbox.sourceware.org/gdb-patches/cover.1730731085.git.aburgess@redhat.com But that series is pretty long, and wasn't getting reviewed, so I'm posted the series in parts now. Before the previous commit, GDB behaved like this: $ gdb -eiex 'set startup-with-shell off' --args /tmp/exec '$FOO' (gdb) show args Argument list to give program being debugged when it is started is "$FOO". Notice that with 'startup-with-shell' off, the argument was left as just '$FOO'. But after the previous commit, this changed to: $ gdb -eiex 'set startup-with-shell off' --args /tmp/exec '$FOO' (gdb) show args Argument list to give program being debugged when it is started is "\$FOO". Now the '$' is escaped with a backslash. This commit restores the original behaviour, as this is (currently) the only way to unquoted shell special characters into arguments from the GDB command line. The series that I listed above includes a new command line option for GDB which provides a better approach for controlling the quoting of special shell characters, but that work requires these patches to be merged first. I've split out the core of construct_inferior_arguments into the new function escape_characters, which takes a set of characters to escape. Then the two functions escape_shell_characters and escape_gdb_characters call escape_characters with the appropriate character sets. Finally, construct_inferior_arguments, now takes a boolean which indicates if we should perform full shell escaping, or just perform the reduced escaping. I've updated all uses of construct_inferior_arguments to pass a suitable value to indicate what escaping to perform (mostly just 'true', but one case in main.c is different), also I've updated inferior::set_args to take the same boolean flag, and pass it through to construct_inferior_arguments. Tested-By: Guinevere Larsen <guinevere@redhat.com>
This commit is contained in:
@@ -1174,7 +1174,7 @@ core_target_open (const char *arg, int from_tty)
|
||||
for (const gdb::unique_xmalloc_ptr<char> &a : ctx.args ())
|
||||
argv.push_back (a.get ());
|
||||
gdb::array_view<char * const> view (argv.data (), argv.size ());
|
||||
current_inferior ()->set_args (view);
|
||||
current_inferior ()->set_args (view, true);
|
||||
|
||||
/* And now copy the environment. */
|
||||
current_inferior ()->environment = ctx.environment ();
|
||||
|
||||
@@ -167,9 +167,10 @@ inferior::tty ()
|
||||
/* See inferior.h. */
|
||||
|
||||
void
|
||||
inferior::set_args (gdb::array_view<char * const> args)
|
||||
inferior::set_args (gdb::array_view<char * const> args,
|
||||
bool escape_shell_char)
|
||||
{
|
||||
set_args (construct_inferior_arguments (args));
|
||||
set_args (construct_inferior_arguments (args, escape_shell_char));
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -522,8 +522,11 @@ public:
|
||||
m_args = std::move (args);
|
||||
};
|
||||
|
||||
/* Set the argument string from some strings. */
|
||||
void set_args (gdb::array_view<char * const> args);
|
||||
/* Set the argument string from some strings in ARGS. When
|
||||
ESCAPE_SHELL_CHAR is true all special shell characters in ARGS are
|
||||
escaped, When false only the characters that GDB sees as special will
|
||||
be escaped. See construct_inferior_arguments for more details. */
|
||||
void set_args (gdb::array_view<char * const> args, bool escape_shell_char);
|
||||
|
||||
/* Get the argument string to use when running this inferior.
|
||||
|
||||
|
||||
@@ -1078,7 +1078,8 @@ captured_main_1 (struct captured_main_args *context)
|
||||
execarg = argv[optind];
|
||||
++optind;
|
||||
current_inferior ()->set_args
|
||||
(gdb::array_view<char * const> (&argv[optind], argc - optind));
|
||||
(gdb::array_view<char * const> (&argv[optind], argc - optind),
|
||||
startup_with_shell);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -929,7 +929,7 @@ infpy_set_args (PyObject *self, PyObject *value, void *closure)
|
||||
for (const auto &arg : args)
|
||||
argvec.push_back (arg.get ());
|
||||
gdb::array_view<char * const> view (argvec.data (), argvec.size ());
|
||||
inf->inferior->set_args (view);
|
||||
inf->inferior->set_args (view, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -3465,7 +3465,7 @@ handle_v_run (char *own_buf)
|
||||
else
|
||||
program_path.set (new_program_name.get ());
|
||||
|
||||
program_args = construct_inferior_arguments (new_argv.get ());
|
||||
program_args = construct_inferior_arguments (new_argv.get (), true);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -4355,7 +4355,7 @@ captured_main (int argc, char *argv[])
|
||||
|
||||
int n = argc - (next_arg - argv);
|
||||
program_args
|
||||
= construct_inferior_arguments ({&next_arg[1], &next_arg[n]});
|
||||
= construct_inferior_arguments ({&next_arg[1], &next_arg[n]}, true);
|
||||
|
||||
/* Wait till we are at first instruction in program. */
|
||||
target_create_inferior (program_path.get (), program_args);
|
||||
|
||||
@@ -24,74 +24,131 @@
|
||||
|
||||
bool startup_with_shell = true;
|
||||
|
||||
/* See common-inferior.h. */
|
||||
/* Escape characters in ARG and return an updated string. The string
|
||||
SPECIAL contains the set of characters that must be escaped. SPECIAL
|
||||
must not be nullptr, and it is assumed that SPECIAL contains the newline
|
||||
'\n' character. It is assumed that ARG is not nullptr, but ARG can
|
||||
be the empty string. */
|
||||
|
||||
std::string
|
||||
construct_inferior_arguments (gdb::array_view<char * const> argv)
|
||||
static std::string
|
||||
escape_characters (const char *arg, const char *special)
|
||||
{
|
||||
gdb_assert (special != nullptr);
|
||||
gdb_assert (arg != nullptr);
|
||||
|
||||
std::string result;
|
||||
|
||||
#ifdef __MINGW32__
|
||||
static const char quote = '"';
|
||||
#else
|
||||
static const char quote = '\'';
|
||||
#endif
|
||||
|
||||
/* Need to handle empty arguments specially. */
|
||||
if (arg[0] == '\0')
|
||||
{
|
||||
result += quote;
|
||||
result += quote;
|
||||
}
|
||||
/* The special character handling code here assumes that if SPECIAL is
|
||||
not nullptr, then SPECIAL will contain '\n'. This is true for all our
|
||||
current usages, but if this ever changes in the future the following
|
||||
might need reworking. */
|
||||
else
|
||||
{
|
||||
#ifdef __MINGW32__
|
||||
bool quoted = false;
|
||||
|
||||
if (strpbrk (argv[i], special))
|
||||
{
|
||||
quoted = true;
|
||||
result += quote;
|
||||
}
|
||||
#endif
|
||||
for (const char *cp = arg; *cp; ++cp)
|
||||
{
|
||||
if (*cp == '\n')
|
||||
{
|
||||
/* A newline cannot be quoted with a backslash (it just
|
||||
disappears), only by putting it inside quotes. */
|
||||
result += quote;
|
||||
result += '\n';
|
||||
result += quote;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef __MINGW32__
|
||||
if (*cp == quote)
|
||||
#else
|
||||
if (strchr (special, *cp) != nullptr)
|
||||
#endif
|
||||
result += '\\';
|
||||
result += *cp;
|
||||
}
|
||||
}
|
||||
#ifdef __MINGW32__
|
||||
if (quoted)
|
||||
result += quote;
|
||||
#endif
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Return a version of ARG that has special shell characters escaped. */
|
||||
|
||||
static std::string
|
||||
escape_shell_characters (const char *arg)
|
||||
{
|
||||
#ifdef __MINGW32__
|
||||
/* This holds all the characters considered special to the
|
||||
Windows shells. */
|
||||
static const char special[] = "\"!&*|[]{}<>?`~^=;, \t\n";
|
||||
static const char quote = '"';
|
||||
#else
|
||||
/* This holds all the characters considered special to the
|
||||
typical Unix shells. We include `^' because the SunOS
|
||||
/bin/sh treats it as a synonym for `|'. */
|
||||
static const char special[] = "\"!#$&*()\\|[]{}<>?'`~^; \t\n";
|
||||
static const char quote = '\'';
|
||||
#endif
|
||||
for (int i = 0; i < argv.size (); ++i)
|
||||
{
|
||||
if (i > 0)
|
||||
result += ' ';
|
||||
|
||||
/* Need to handle empty arguments specially. */
|
||||
if (argv[i][0] == '\0')
|
||||
{
|
||||
result += quote;
|
||||
result += quote;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef __MINGW32__
|
||||
bool quoted = false;
|
||||
return escape_characters (arg, special);
|
||||
}
|
||||
|
||||
if (strpbrk (argv[i], special))
|
||||
{
|
||||
quoted = true;
|
||||
result += quote;
|
||||
}
|
||||
#endif
|
||||
for (char *cp = argv[i]; *cp != '\0'; ++cp)
|
||||
{
|
||||
if (*cp == '\n')
|
||||
{
|
||||
/* A newline cannot be quoted with a backslash (it
|
||||
just disappears), only by putting it inside
|
||||
quotes. */
|
||||
result += quote;
|
||||
result += '\n';
|
||||
result += quote;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Return a version of ARG that has quote characters and white space
|
||||
characters escaped. These are the characters that GDB sees as special
|
||||
when splitting a string into separate arguments. */
|
||||
|
||||
static std::string
|
||||
escape_gdb_characters (const char * arg)
|
||||
{
|
||||
#ifdef __MINGW32__
|
||||
if (*cp == quote)
|
||||
static const char special[] = "\" \t\n";
|
||||
#else
|
||||
if (strchr (special, *cp) != NULL)
|
||||
static const char special[] = "\"' \t\n";
|
||||
#endif
|
||||
result += '\\';
|
||||
result += *cp;
|
||||
}
|
||||
}
|
||||
#ifdef __MINGW32__
|
||||
if (quoted)
|
||||
result += quote;
|
||||
#endif
|
||||
}
|
||||
|
||||
return escape_characters (arg, special);
|
||||
}
|
||||
|
||||
/* See common-inferior.h. */
|
||||
|
||||
std::string
|
||||
construct_inferior_arguments (gdb::array_view<char * const> argv,
|
||||
bool escape_shell_char)
|
||||
{
|
||||
/* Select the desired escape function. */
|
||||
const auto escape_func = (escape_shell_char
|
||||
? escape_shell_characters
|
||||
: escape_gdb_characters);
|
||||
|
||||
std::string result;
|
||||
|
||||
for (const char *a : argv)
|
||||
{
|
||||
if (!result.empty ())
|
||||
result += " ";
|
||||
|
||||
result += escape_func (a);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -52,9 +52,13 @@ extern const std::string &get_inferior_cwd ();
|
||||
the target is started up with a shell. */
|
||||
extern bool startup_with_shell;
|
||||
|
||||
/* Compute command-line string given argument vector. This does the
|
||||
same shell processing as fork_inferior. */
|
||||
/* Combine elements of ARGV into a single string, placing a single
|
||||
whitespace character between each element. When ESCAPE_SHELL_CHAR is
|
||||
true then any special shell characters in elemets of ARGV will be
|
||||
escaped. When ESCAPE_SHELL_CHAR is false only the characters that GDB
|
||||
sees as special (quotes and whitespace) are escaped. */
|
||||
extern std::string
|
||||
construct_inferior_arguments (gdb::array_view<char * const>);
|
||||
construct_inferior_arguments (gdb::array_view<char * const> argv,
|
||||
bool escape_shell_char);
|
||||
|
||||
#endif /* GDBSUPPORT_COMMON_INFERIOR_H */
|
||||
|
||||
Reference in New Issue
Block a user