aboutsummaryrefslogtreecommitdiff
path: root/gdbserver/server.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gdbserver/server.cc')
-rw-r--r--gdbserver/server.cc576
1 files changed, 386 insertions, 190 deletions
diff --git a/gdbserver/server.cc b/gdbserver/server.cc
index 0ce40ee..0459b72 100644
--- a/gdbserver/server.cc
+++ b/gdbserver/server.cc
@@ -22,7 +22,6 @@
#include "tdesc.h"
#include "gdbsupport/rsp-low.h"
#include "gdbsupport/signals-state-save-restore.h"
-#include <ctype.h>
#include <unistd.h>
#if HAVE_SIGNAL_H
#include <signal.h>
@@ -51,6 +50,9 @@
#include "gdbsupport/scoped_restore.h"
#include "gdbsupport/search.h"
#include "gdbsupport/gdb_argv_vec.h"
+#include "gdbsupport/remote-args.h"
+
+#include <getopt.h>
/* PBUFSIZ must also be at least as big as IPA_CMD_BUF_SIZE, because
the client state data is passed directly to some agent
@@ -140,6 +142,7 @@ unsigned long signal_pid;
in gdbserver, for the sake of testing GDB against stubs that don't
support them. */
bool disable_packet_vCont;
+bool disable_packet_vCont_step;
bool disable_packet_Tthread;
bool disable_packet_qC;
bool disable_packet_qfThreadInfo;
@@ -1017,20 +1020,15 @@ handle_general_set (char *own_buf)
});
}
- for (const auto &iter : set_options)
- {
- thread_info *thread = iter.first;
- gdb_thread_options options = iter.second;
-
- if (thread->thread_options != options)
- {
- threads_debug_printf ("[options for %s are now %s]\n",
- target_pid_to_str (thread->id).c_str (),
- to_string (options).c_str ());
+ for (const auto &[thread, options] : set_options)
+ if (thread->thread_options != options)
+ {
+ threads_debug_printf ("[options for %s are now %s]\n",
+ target_pid_to_str (thread->id).c_str (),
+ to_string (options).c_str ());
- thread->thread_options = options;
- }
- }
+ thread->thread_options = options;
+ }
write_ok (own_buf);
return;
@@ -1428,7 +1426,7 @@ parse_debug_format_options (const char *arg, int is_monitor)
debug_timestamp = 0;
/* First remove leading spaces, for "monitor set debug-format". */
- while (isspace (*arg))
+ while (c_isspace (*arg))
++arg;
std::vector<gdb::unique_xmalloc_ptr<char>> options
@@ -1474,8 +1472,8 @@ parse_debug_format_options (const char *arg, int is_monitor)
struct debug_opt
{
/* NAME is the name of this debug option, this should be a simple string
- containing no whitespace, starting with a letter from isalpha(), and
- contain only isalnum() characters and '_' underscore and '-' hyphen.
+ containing no whitespace, starting with a letter from c_isalpha(), and
+ contain only c_isalnum() characters and '_' underscore and '-' hyphen.
SETTER is a callback function used to set the debug variable. This
callback will be passed true to enable the debug setting, or false to
@@ -1484,7 +1482,7 @@ struct debug_opt
: m_name (name),
m_setter (setter)
{
- gdb_assert (isalpha (*name));
+ gdb_assert (c_isalpha (*name));
}
/* Called to enable or disable the debug setting. */
@@ -2746,6 +2744,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
}
else if (feature == "error-message+")
cs.error_message_supported = true;
+ else if (feature == "single-inf-arg+")
+ cs.single_inferior_argument = true;
else
{
/* Move the unknown features all together. */
@@ -2863,7 +2863,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
{
char *end_buf = own_buf + strlen (own_buf);
sprintf (end_buf, ";QThreadOptions=%s",
- phex_nz (supported_options, sizeof (supported_options)));
+ phex_nz (supported_options));
}
strcat (own_buf, ";QThreadEvents+");
@@ -2873,6 +2873,9 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
if (target_supports_memory_tagging ())
strcat (own_buf, ";memory-tagging+");
+ if (cs.single_inferior_argument)
+ strcat (own_buf, ";single-inf-arg+");
+
/* Reinitialize components as needed for the new connection. */
hostio_handle_new_gdb_connection ();
target_handle_new_gdb_connection ();
@@ -3090,6 +3093,34 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
return;
}
+ if (strcmp ("qExecAndArgs", own_buf) == 0)
+ {
+ if (program_path.get () == nullptr)
+ sprintf (own_buf, "U");
+ else
+ {
+ std::string packet ("S;");
+
+ packet += bin2hex ((const gdb_byte *) program_path.get (),
+ strlen (program_path.get ()));
+ packet += ";";
+
+ packet += bin2hex ((const gdb_byte *) program_args.c_str (),
+ program_args.length ());
+ packet += ";";
+
+ if (packet.size () > PBUFSIZ)
+ {
+ sprintf (own_buf, "E.Program name and arguments too long.");
+ return;
+ }
+
+ strcpy (own_buf, packet.c_str ());
+ *new_packet_len_p = packet.size ();
+ }
+ return;
+ }
+
/* Otherwise we didn't know what packet it was. Say we didn't
understand it. */
own_buf[0] = 0;
@@ -3465,7 +3496,20 @@ handle_v_run (char *own_buf)
else
program_path.set (new_program_name.get ());
- program_args = construct_inferior_arguments (new_argv.get (), true);
+ if (cs.single_inferior_argument)
+ {
+ if (new_argv.get ().size () > 1)
+ {
+ write_enn (own_buf);
+ return;
+ }
+ else if (new_argv.get ().size () == 1)
+ program_args = std::string (new_argv.get ()[0]);
+ else
+ program_args.clear ();
+ }
+ else
+ program_args = gdb::remote_args::join (new_argv.get ());
try
{
@@ -3540,9 +3584,10 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len)
{
strcpy (own_buf, "vCont;c;C;t");
- if (target_supports_hardware_single_step ()
- || target_supports_software_single_step ()
- || !cs.vCont_supported)
+ if (!disable_packet_vCont_step
+ && (target_supports_hardware_single_step ()
+ || target_supports_software_single_step ()
+ || !cs.vCont_supported))
{
/* If target supports single step either by hardware or by
software, add actions s and S to the list of supported
@@ -3812,7 +3857,7 @@ static void
gdbserver_version (void)
{
printf ("GNU gdbserver %s%s\n"
- "Copyright (C) 2024 Free Software Foundation, Inc.\n"
+ "Copyright (C) 2025 Free Software Foundation, Inc.\n"
"gdbserver is free software, covered by the "
"GNU General Public License.\n"
"This gdbserver was configured as \"%s\"\n",
@@ -3852,10 +3897,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 substitution 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 substitution in the shell\n"
+ " are done for ARGS on UNIX-like systems.\n"
"\n"
"Debug options:\n"
"\n"
@@ -3875,7 +3930,7 @@ gdbserver_usage (FILE *stream)
" --disable-packet=OPT1[,OPT2,...]\n"
" Disable support for RSP packets or features.\n"
" Options:\n"
- " vCont, T, Tthread, qC, qfThreadInfo and \n"
+ " vCont, vConts, T, Tthread, qC, qfThreadInfo and\n"
" threads (disable all threading packets).\n"
"\n"
"For more information, consult the GDB manual (available as on-line \n"
@@ -4107,15 +4162,11 @@ static void test_registers_raw_compare_zero_length ()
[[noreturn]] static void
captured_main (int argc, char *argv[])
{
- int bad_attach;
int pid;
- char *arg_end;
- const char *port = NULL;
- char **next_arg = &argv[1];
- volatile int multi_mode = 0;
- volatile int attach = 0;
- int was_running;
+ 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;
@@ -4134,184 +4185,323 @@ captured_main (int argc, char *argv[])
safe_strerror (errno));
}
- while (*next_arg != NULL && **next_arg == '-')
- {
- if (strcmp (*next_arg, "--version") == 0)
- {
- gdbserver_version ();
- exit (0);
- }
- else if (strcmp (*next_arg, "--help") == 0)
- {
- gdbserver_usage (stdout);
- exit (0);
- }
- else if (strcmp (*next_arg, "--attach") == 0)
- attach = 1;
- else if (strcmp (*next_arg, "--multi") == 0)
- multi_mode = 1;
- else if (strcmp (*next_arg, "--wrapper") == 0)
- {
- char **tmp;
-
- next_arg++;
-
- tmp = next_arg;
- while (*next_arg != NULL && strcmp (*next_arg, "--") != 0)
- {
- wrapper_argv += *next_arg;
- wrapper_argv += ' ';
- next_arg++;
- }
-
- if (!wrapper_argv.empty ())
- {
- /* Erase the last whitespace. */
- wrapper_argv.erase (wrapper_argv.end () - 1);
- }
+ enum opts { OPT_VERSION = 1, OPT_HELP, OPT_ATTACH, OPT_MULTI, OPT_WRAPPER,
+ 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_NO_ESCAPE
+ };
- if (next_arg == tmp || *next_arg == NULL)
- {
- gdbserver_usage (stderr);
- exit (1);
- }
+ static struct option longopts[] =
+ {
+ {"version", no_argument, nullptr, OPT_VERSION},
+ {"help", no_argument, nullptr, OPT_HELP},
+ {"attach", no_argument, nullptr, OPT_ATTACH},
+ {"multi", no_argument, nullptr, OPT_MULTI},
+ {"wrapper", no_argument, nullptr, OPT_WRAPPER},
+ {"debug", optional_argument, nullptr, OPT_DEBUG},
+ {"debug-file", required_argument, nullptr, OPT_DEBUG_FILE},
+ {"debug-format", required_argument, nullptr, OPT_DEBUG_FORMAT},
+ /* --disable-packet is optional_argument only so that we can print a
+ better help list when the argument is missing. */
+ {"disable-packet", optional_argument, nullptr, OPT_DISABLE_PACKET},
+ {"disable-randomization", no_argument, nullptr,
+ OPT_DISABLE_RANDOMIZATION},
+ {"no-disable-randomization", no_argument, nullptr,
+ OPT_NO_DISABLE_RANDOMIZATION},
+ {"startup-with-shell", no_argument, nullptr, OPT_STARTUP_WITH_SHELL},
+ {"no-startup-with-shell", no_argument, nullptr,
+ 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}
+ };
- /* Consume the "--". */
- *next_arg = NULL;
- }
- else if (startswith (*next_arg, "--debug="))
- {
- try
- {
- parse_debug_options ((*next_arg) + sizeof ("--debug=") - 1);
- }
- catch (const gdb_exception_error &exception)
- {
- fflush (stdout);
- fprintf (stderr, "gdbserver: %s\n", exception.what ());
- exit (1);
- }
- }
- else if (strcmp (*next_arg, "--debug") == 0)
+ /* Ask getopt_long not to print error messages, we'll do that ourselves.
+ Look for handling of '?' from getopt_long. */
+ opterr = 0;
+
+ int optc, longindex;
+
+ /* The '+' passed to getopt_long here stops ARGV being reordered. In a
+ command line like: 'gdbserver PORT program --arg1 --arg2', the
+ '--arg1' and '--arg2' are arguments to 'program', not to gdbserver.
+ If getopt_long is free to reorder ARGV then it will try to steal those
+ arguments for itself. */
+ while ((longindex = -1,
+ optc = getopt_long (argc, argv, "+:", longopts, &longindex)) != -1)
+ {
+ /* As a GNU extension, getopt_long supports '--arg value' form,
+ without an '=' symbol between the 'arg' and the 'value'. This
+ block aids in supporting this form.
+
+ If we found a matching entry in LONGOPTS, the entry has an
+ optional argument, and OPTARG is NULL, then this indicates that we
+ saw the '--arg value' form. Look at the next ARGV entry to see if
+ it exists, and doesn't look like a port number, or the start of
+ another argument. If this is the case, then make the next ARGV
+ entry the argument value. Otherwise, continue with no
+ argument.
+
+ If we found a matching entry in LONGOPTS, the entry has a required
+ argument, then OPTARG will not be NULL. In this case, if the
+ start of OPTARG is the start of the previous ARGV entry, then this
+ indicates we saw the '--arg value' form. If OPTARG looks like a
+ port number, or the start of another argument, then assume the
+ user didn't in fact pass a value, but forgot. Pretend we are
+ missing the argument value. */
+ if (longindex != -1
+ && ((longopts[longindex].has_arg == optional_argument
+ &&optarg == nullptr)
+ || (longopts[longindex].has_arg == required_argument
+ && optarg == argv[optind - 1])))
{
- try
- {
- parse_debug_options ("");
- }
- catch (const gdb_exception_error &exception)
+ if (longopts[longindex].has_arg == optional_argument)
{
- fflush (stdout);
- fprintf (stderr, "gdbserver: %s\n", exception.what ());
- exit (1);
+ /* Claim the next entry from ARGV as the argument value. */
+ optarg = argv[optind];
+ optind++;
}
- }
- else if (startswith (*next_arg, "--debug-format="))
- {
- std::string error_msg
- = parse_debug_format_options ((*next_arg)
- + sizeof ("--debug-format=") - 1, 0);
+ else
+ gdb_assert (optarg != nullptr);
- if (!error_msg.empty ())
+ if (optarg == nullptr
+ || strcmp (optarg, "-") == 0
+ || strcmp (optarg, STDIO_CONNECTION_NAME) == 0
+ || startswith (optarg, "--")
+ || strchr (optarg, ':') != nullptr)
{
- fprintf (stderr, "%s", error_msg.c_str ());
- exit (1);
+ /* OPTARG is NULL, looks like a port number, or could be the
+ start of another argument. Clear OPTARG as we don't have
+ an argument, and decrement OPTIND so the next call to
+ getopt will process this as an argument. */
+ optarg = nullptr;
+ optind--;
+
+ /* For required arguments, if we don't have an argument, then
+ this is an error, set OPTC to reflect this. */
+ if (longopts[longindex].has_arg == required_argument)
+ optc = ':';
}
}
- else if (startswith (*next_arg, "--debug-file="))
- debug_set_output ((*next_arg) + sizeof ("--debug-file=") -1);
- else if (strcmp (*next_arg, "--disable-packet") == 0)
+
+ switch (optc)
{
- gdbserver_show_disableable (stdout);
+ case OPT_VERSION:
+ gdbserver_version ();
exit (0);
- }
- else if (startswith (*next_arg, "--disable-packet="))
- {
- char *packets = *next_arg += sizeof ("--disable-packet=") - 1;
- char *saveptr;
- for (char *tok = strtok_r (packets, ",", &saveptr);
- tok != NULL;
- tok = strtok_r (NULL, ",", &saveptr))
- {
- if (strcmp ("vCont", tok) == 0)
- disable_packet_vCont = true;
- else if (strcmp ("Tthread", tok) == 0)
- disable_packet_Tthread = true;
- else if (strcmp ("qC", tok) == 0)
- disable_packet_qC = true;
- else if (strcmp ("qfThreadInfo", tok) == 0)
- disable_packet_qfThreadInfo = true;
- else if (strcmp ("T", tok) == 0)
- disable_packet_T = true;
- else if (strcmp ("threads", tok) == 0)
- {
+
+ case OPT_HELP:
+ gdbserver_usage (stdout);
+ exit (0);
+
+ case OPT_ATTACH:
+ attach = true;
+ break;
+
+ case OPT_MULTI:
+ multi_mode = true;
+ break;
+
+ case OPT_WRAPPER:
+ {
+ int original_optind = optind;
+
+ while (argv[optind] != nullptr
+ && strcmp (argv[optind], "--") != 0)
+ {
+ wrapper_argv += argv[optind];
+ wrapper_argv += ' ';
+ ++optind;
+ }
+
+ if (!wrapper_argv.empty ())
+ {
+ /* Erase the last whitespace. */
+ wrapper_argv.erase (wrapper_argv.end () - 1);
+ }
+
+ if (original_optind == optind || argv[optind] == nullptr)
+ {
+ gdbserver_usage (stderr);
+ exit (1);
+ }
+
+ /* Consume the "--". */
+ ++optind;
+ }
+ break;
+
+ case OPT_DEBUG:
+ {
+ const char *debug_opt = (optarg == nullptr) ? "" : optarg;
+ try
+ {
+ parse_debug_options (debug_opt);
+ }
+ catch (const gdb_exception_error &exception)
+ {
+ fflush (stdout);
+ fprintf (stderr, "gdbserver: %s\n", exception.what ());
+ exit (1);
+ }
+ }
+ break;
+
+ case OPT_DEBUG_FILE:
+ {
+ gdb_assert (optarg != nullptr);
+ debug_set_output (optarg);
+ }
+ break;
+
+ case OPT_DEBUG_FORMAT:
+ {
+ gdb_assert (optarg != nullptr);
+ std::string error_msg
+ = parse_debug_format_options (optarg, 0);
+
+ if (!error_msg.empty ())
+ {
+ fprintf (stderr, "%s", error_msg.c_str ());
+ exit (1);
+ }
+ }
+ break;
+
+ case OPT_DISABLE_PACKET:
+ {
+ char *packets = optarg;
+ if (packets == nullptr)
+ {
+ gdbserver_show_disableable (stdout);
+ exit (1);
+ }
+ char *saveptr;
+ for (char *tok = strtok_r (packets, ",", &saveptr);
+ tok != nullptr;
+ tok = strtok_r (nullptr, ",", &saveptr))
+ {
+ if (strcmp ("vCont", tok) == 0)
disable_packet_vCont = true;
+ else if (strcmp ("vConts", tok) == 0)
+ disable_packet_vCont_step = true;
+ else if (strcmp ("Tthread", tok) == 0)
disable_packet_Tthread = true;
+ else if (strcmp ("qC", tok) == 0)
disable_packet_qC = true;
+ else if (strcmp ("qfThreadInfo", tok) == 0)
disable_packet_qfThreadInfo = true;
- }
- else
- {
- fprintf (stderr, "Don't know how to disable \"%s\".\n\n",
- tok);
- gdbserver_show_disableable (stderr);
- exit (1);
- }
- }
- }
- else if (strcmp (*next_arg, "-") == 0)
- {
- /* "-" specifies a stdio connection and is a form of port
- specification. */
- port = STDIO_CONNECTION_NAME;
+ else if (strcmp ("T", tok) == 0)
+ disable_packet_T = true;
+ else if (strcmp ("threads", tok) == 0)
+ {
+ disable_packet_vCont = true;
+ disable_packet_Tthread = true;
+ disable_packet_qC = true;
+ disable_packet_qfThreadInfo = true;
+ }
+ else
+ {
+ fprintf (stderr, "Don't know how to disable \"%s\".\n\n",
+ tok);
+ gdbserver_show_disableable (stderr);
+ exit (1);
+ }
+ }
+ }
+ break;
- /* Implying --once here prevents a hang after stdin has been closed. */
- run_once = true;
+ case OPT_DISABLE_RANDOMIZATION:
+ cs.disable_randomization = 1;
+ break;
- next_arg++;
+ case OPT_NO_DISABLE_RANDOMIZATION:
+ cs.disable_randomization = 0;
break;
- }
- else if (strcmp (*next_arg, "--disable-randomization") == 0)
- cs.disable_randomization = 1;
- else if (strcmp (*next_arg, "--no-disable-randomization") == 0)
- cs.disable_randomization = 0;
- else if (strcmp (*next_arg, "--startup-with-shell") == 0)
- startup_with_shell = true;
- else if (strcmp (*next_arg, "--no-startup-with-shell") == 0)
- startup_with_shell = false;
- else if (strcmp (*next_arg, "--once") == 0)
- run_once = true;
- else if (strcmp (*next_arg, "--selftest") == 0)
- selftest = true;
- else if (startswith (*next_arg, "--selftest="))
- {
- selftest = true;
+ case OPT_STARTUP_WITH_SHELL:
+ startup_with_shell = true;
+ break;
+
+ case OPT_NO_STARTUP_WITH_SHELL:
+ startup_with_shell = false;
+ break;
+
+ case OPT_ONCE:
+ run_once = true;
+ break;
+
+ case OPT_SELFTEST:
+ {
+ selftest = true;
+ if (optarg != nullptr)
+ {
#if GDB_SELF_TEST
- const char *filter = *next_arg + strlen ("--selftest=");
- if (*filter == '\0')
- {
- fprintf (stderr, _("Error: selftest filter is empty.\n"));
- exit (1);
- }
+ if (*optarg == '\0')
+ {
+ fprintf (stderr, _("Error: selftest filter is empty.\n"));
+ exit (1);
+ }
- selftest_filters.push_back (filter);
+ selftest_filters.push_back (optarg);
#endif
- }
- else
- {
- fprintf (stderr, "Unknown argument: %s\n", *next_arg);
+ }
+ }
+ break;
+
+ case OPT_NO_ESCAPE:
+ escape_args = false;
+ break;
+
+ case ':':
+ case '?':
+ /* Figuring out which element of ARGV contained the invalid
+ argument is not simple. There are a couple of cases we need
+ to consider.
+
+ (1) Something like '-x'. gdbserver doesn't support single
+ character options, so a '-' followed by a character is
+ always invalid. In this case global OPTOPT will be set to
+ 'x', and global OPTIND will point to the next ARGV entry.
+
+ (2) Something like '-xyz'. gdbserver doesn't support single
+ dash arguments for its command line options. The
+ getopt_long call treats this like '-x -y -z', in which
+ case global OPTOPT is set to 'x' and global OPTIND will
+ point to this ARGV entry.
+
+ (3) Something like '--unknown'. This is just an unknown
+ double dash argument. Global OPTOPT is set to '\0', and
+ global OPTIND points to the next ARGV entry. */
+ std::string bad_arg;
+ if (optopt == '\0' || argv[optind] == nullptr
+ || argv[optind][0] != '-' || argv[optind][1] != optopt)
+ bad_arg = argv[optind - 1];
+ else
+ bad_arg = argv[optind];
+
+ if (optc == '?')
+ fprintf (stderr, _("Unknown argument: %s\n"), bad_arg.c_str ());
+ else
+ fprintf (stderr, _("Missing argument value for: %s\n"),
+ bad_arg.c_str ());
exit (1);
}
-
- next_arg++;
- continue;
}
- if (port == NULL)
+ const char *port = argv[optind];
+ ++optind;
+ if (port != nullptr && strcmp (port, "-") == 0)
{
- port = *next_arg;
- next_arg++;
+ port = STDIO_CONNECTION_NAME;
+
+ /* Implying --once here prevents a hang after stdin has been closed. */
+ run_once = true;
}
+
+ char **next_arg = &argv[optind];
if ((port == NULL || (!attach && !multi_mode && *next_arg == NULL))
&& !selftest)
{
@@ -4332,24 +4522,25 @@ captured_main (int argc, char *argv[])
if (port != NULL)
remote_prepare (port);
- bad_attach = 0;
+ bool bad_attach = false;
pid = 0;
/* --attach used to come after PORT, so allow it there for
compatibility. */
if (*next_arg != NULL && strcmp (*next_arg, "--attach") == 0)
{
- attach = 1;
+ attach = true;
next_arg++;
}
+ char *arg_end;
if (attach
&& (*next_arg == NULL
|| (*next_arg)[0] == '\0'
|| (pid = strtoul (*next_arg, &arg_end, 0)) == 0
|| *arg_end != '\0'
|| next_arg[1] != NULL))
- bad_attach = 1;
+ bad_attach = true;
if (bad_attach)
{
@@ -4382,9 +4573,13 @@ captured_main (int argc, char *argv[])
{
program_path.set (next_arg[0]);
+ if (program_path.get () == nullptr)
+ error (_("No program to debug"));
+
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);
@@ -4414,11 +4609,12 @@ captured_main (int argc, char *argv[])
if (current_thread != nullptr)
current_process ()->dlls_changed = false;
+ bool was_running;
if (cs.last_status.kind () == TARGET_WAITKIND_EXITED
|| cs.last_status.kind () == TARGET_WAITKIND_SIGNALLED)
- was_running = 0;
+ was_running = false;
else
- was_running = 1;
+ was_running = true;
if (!was_running && !multi_mode)
error ("No program to debug");