/* Functions to deal with the inferior being executed on GDB or
GDBserver.
Copyright (C) 2019-2024 Free Software Foundation, Inc.
This file is part of GDB.
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 "gdbsupport/common-inferior.h"
/* See common-inferior.h. */
bool startup_with_shell = true;
/* 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. */
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";
#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";
#endif
return escape_characters (arg, special);
}
/* 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__
static const char special[] = "\" \t\n";
#else
static const char special[] = "\"' \t\n";
#endif
return escape_characters (arg, special);
}
/* See common-inferior.h. */
std::string
construct_inferior_arguments (gdb::array_view 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;
}