/* Main code for remote server for GDB.
- Copyright (C) 1989-2017 Free Software Foundation, Inc.
+ Copyright (C) 1989-2018 Free Software Foundation, Inc.
This file is part of GDB.
#include "common-inferior.h"
#include "job-control.h"
#include "environ.h"
+#include "filenames.h"
+#include "pathstuff.h"
#include "common/selftest.h"
break; \
}
+/* String containing the current directory (what getwd would return). */
+
+char *current_directory;
+
/* The environment to pass to the inferior when creating it. */
static gdb_environ our_environ;
space randomization feature before starting an inferior. */
int disable_randomization = 1;
-static char *program_name = NULL;
+static struct {
+ /* Set the PROGRAM_PATH. Here we adjust the path of the provided
+ binary if needed. */
+ void set (gdb::unique_xmalloc_ptr<char> &&path)
+ {
+ m_path = std::move (path);
+
+ /* Make sure we're using the absolute path of the inferior when
+ creating it. */
+ if (!contains_dir_separator (m_path.get ()))
+ {
+ int reg_file_errno;
+
+ /* Check if the file is in our CWD. If it is, then we prefix
+ its name with CURRENT_DIRECTORY. Otherwise, we leave the
+ name as-is because we'll try searching for it in $PATH. */
+ if (is_regular_file (m_path.get (), ®_file_errno))
+ m_path = gdb_abspath (m_path.get ());
+ }
+ }
+
+ /* Return the PROGRAM_PATH. */
+ char *get ()
+ { return m_path.get (); }
+
+private:
+ /* The program name, adjusted if needed. */
+ gdb::unique_xmalloc_ptr<char> m_path;
+} program_path;
static std::vector<char *> program_args;
static std::string wrapper_argv;
char *
get_exec_file (int err)
{
- if (err && program_name == NULL)
+ if (err && program_path.get () == NULL)
error (_("No executable file specified."));
- return program_name;
+ return program_path.get ();
}
/* See server.h. */
/* Handle btrace enabling in BTS format. */
-static const char *
+static void
handle_btrace_enable_bts (struct thread_info *thread)
{
if (thread->btrace != NULL)
- return "E.Btrace already enabled.";
+ error (_("Btrace already enabled."));
current_btrace_conf.format = BTRACE_FORMAT_BTS;
thread->btrace = target_enable_btrace (thread->id, ¤t_btrace_conf);
- if (thread->btrace == NULL)
- return "E.Could not enable btrace.";
-
- return NULL;
}
/* Handle btrace enabling in Intel Processor Trace format. */
-static const char *
+static void
handle_btrace_enable_pt (struct thread_info *thread)
{
if (thread->btrace != NULL)
- return "E.Btrace already enabled.";
+ error (_("Btrace already enabled."));
current_btrace_conf.format = BTRACE_FORMAT_PT;
thread->btrace = target_enable_btrace (thread->id, ¤t_btrace_conf);
- if (thread->btrace == NULL)
- return "E.Could not enable btrace.";
-
- return NULL;
}
/* Handle btrace disabling. */
-static const char *
+static void
handle_btrace_disable (struct thread_info *thread)
{
if (thread->btrace == NULL)
- return "E.Branch tracing not enabled.";
+ error (_("Branch tracing not enabled."));
if (target_disable_btrace (thread->btrace) != 0)
- return "E.Could not disable branch tracing.";
+ error (_("Could not disable branch tracing."));
thread->btrace = NULL;
- return NULL;
}
/* Handle the "Qbtrace" packet. */
handle_btrace_general_set (char *own_buf)
{
struct thread_info *thread;
- const char *err;
char *op;
if (!startswith (own_buf, "Qbtrace:"))
return -1;
}
- err = NULL;
-
- if (strcmp (op, "bts") == 0)
- err = handle_btrace_enable_bts (thread);
- else if (strcmp (op, "pt") == 0)
- err = handle_btrace_enable_pt (thread);
- else if (strcmp (op, "off") == 0)
- err = handle_btrace_disable (thread);
- else
- err = "E.Bad Qbtrace operation. Use bts, pt, or off.";
+ TRY
+ {
+ if (strcmp (op, "bts") == 0)
+ handle_btrace_enable_bts (thread);
+ else if (strcmp (op, "pt") == 0)
+ handle_btrace_enable_pt (thread);
+ else if (strcmp (op, "off") == 0)
+ handle_btrace_disable (thread);
+ else
+ error (_("Bad Qbtrace operation. Use bts, pt, or off."));
- if (err != 0)
- strcpy (own_buf, err);
- else
- write_ok (own_buf);
+ write_ok (own_buf);
+ }
+ CATCH (exception, RETURN_MASK_ERROR)
+ {
+ sprintf (own_buf, "E.%s", exception.message);
+ }
+ END_CATCH
return 1;
}
req = TRIBOOL_TRUE;
else
{
- char *mode_copy = xstrdup (mode);
-
/* We don't know what this mode is, so complain to GDB. */
sprintf (own_buf, "E.Unknown thread-events mode requested: %s\n",
- mode_copy);
- xfree (mode_copy);
+ mode);
return;
}
if (strcmp (annex, "target.xml") == 0)
{
- const char *ret = tdesc_get_features_xml ((target_desc*) desc);
+ const char *ret = tdesc_get_features_xml (desc);
if (*ret == '@')
return ret + 1;
ARG is the text after "--debug-format=" or "monitor set debug-format".
IS_MONITOR is non-zero if we're invoked via "monitor set debug-format".
This triggers calls to monitor_output.
- The result is NULL if all options were parsed ok, otherwise an error
- message which the caller must free.
+ The result is an empty string if all options were parsed ok, otherwise an
+ error message which the caller must free.
N.B. These commands affect all debug format settings, they are not
cumulative. If a format is not specified, it is turned off.
to gdb's "set debug foo on|off" because we also use this function to
parse "--debug-format=foo,bar". */
-static char *
+static std::string
parse_debug_format_options (const char *arg, int is_monitor)
{
- VEC (char_ptr) *options;
- int ix;
- char *option;
-
/* First turn all debug format options off. */
debug_timestamp = 0;
while (isspace (*arg))
++arg;
- options = delim_string_to_char_ptr_vec (arg, ',');
+ std::vector<gdb::unique_xmalloc_ptr<char>> options
+ = delim_string_to_char_ptr_vec (arg, ',');
- for (ix = 0; VEC_iterate (char_ptr, options, ix, option); ++ix)
+ for (const gdb::unique_xmalloc_ptr<char> &option : options)
{
- if (strcmp (option, "all") == 0)
+ if (strcmp (option.get (), "all") == 0)
{
debug_timestamp = 1;
if (is_monitor)
monitor_output ("All extra debug format options enabled.\n");
}
- else if (strcmp (option, "none") == 0)
+ else if (strcmp (option.get (), "none") == 0)
{
debug_timestamp = 0;
if (is_monitor)
monitor_output ("All extra debug format options disabled.\n");
}
- else if (strcmp (option, "timestamp") == 0)
+ else if (strcmp (option.get (), "timestamp") == 0)
{
debug_timestamp = 1;
if (is_monitor)
continue;
}
else
- {
- char *msg = xstrprintf ("Unknown debug-format argument: \"%s\"\n",
- option);
-
- free_char_ptr_vec (options);
- return msg;
- }
+ return string_printf ("Unknown debug-format argument: \"%s\"\n",
+ option.get ());
}
- free_char_ptr_vec (options);
- return NULL;
+ return std::string ();
}
/* Handle monitor commands not handled by target-specific handlers. */
}
else if (startswith (mon, "set debug-format "))
{
- char *error_msg
+ std::string error_msg
= parse_debug_format_options (mon + sizeof ("set debug-format ") - 1,
1);
- if (error_msg != NULL)
+ if (!error_msg.empty ())
{
- monitor_output (error_msg);
+ monitor_output (error_msg.c_str ());
monitor_show_help ();
write_enn (own_buf);
- xfree (error_msg);
}
}
else if (strcmp (mon, "help") == 0)
enum btrace_read_type type;
int result;
- if (the_target->read_btrace == NULL || writebuf != NULL)
+ if (writebuf != NULL)
return -2;
if (ptid_equal (general_thread, null_ptid)
{
buffer_free (&cache);
- result = target_read_btrace (thread->btrace, &cache, type);
- if (result != 0)
+ TRY
+ {
+ result = target_read_btrace (thread->btrace, &cache, type);
+ if (result != 0)
+ memcpy (own_buf, cache.buffer, cache.used_size);
+ }
+ CATCH (exception, RETURN_MASK_ERROR)
{
- memcpy (own_buf, cache.buffer, cache.used_size);
- return -3;
+ sprintf (own_buf, "E.%s", exception.message);
+ result = -1;
}
+ END_CATCH
+
+ if (result != 0)
+ return -3;
}
else if (offset > cache.used_size)
{
struct thread_info *thread;
int result;
- if (the_target->read_btrace_conf == NULL || writebuf != NULL)
+ if (writebuf != NULL)
return -2;
if (annex[0] != '\0')
{
buffer_free (&cache);
- result = target_read_btrace_conf (thread->btrace, &cache);
- if (result != 0)
+ TRY
+ {
+ result = target_read_btrace_conf (thread->btrace, &cache);
+ if (result != 0)
+ memcpy (own_buf, cache.buffer, cache.used_size);
+ }
+ CATCH (exception, RETURN_MASK_ERROR)
{
- memcpy (own_buf, cache.buffer, cache.used_size);
- return -3;
+ sprintf (own_buf, "E.%s", exception.message);
+ result = -1;
}
+ END_CATCH
+
+ if (result != 0)
+ return -3;
}
else if (offset > cache.used_size)
{
static void
supported_btrace_packets (char *buf)
{
- int btrace_supported = 0;
-
- if (target_supports_btrace (BTRACE_FORMAT_BTS))
- {
- strcat (buf, ";Qbtrace:bts+");
- strcat (buf, ";Qbtrace-conf:bts:size+");
-
- btrace_supported = 1;
- }
-
- if (target_supports_btrace (BTRACE_FORMAT_PT))
- {
- strcat (buf, ";Qbtrace:pt+");
- strcat (buf, ";Qbtrace-conf:pt:size+");
-
- btrace_supported = 1;
- }
-
- if (!btrace_supported)
- return;
-
+ strcat (buf, ";Qbtrace:bts+");
+ strcat (buf, ";Qbtrace-conf:bts:size+");
+ strcat (buf, ";Qbtrace:pt+");
+ strcat (buf, ";Qbtrace-conf:pt:size+");
strcat (buf, ";Qbtrace:off+");
strcat (buf, ";qXfer:btrace:read+");
strcat (buf, ";qXfer:btrace-conf:read+");
{
/* GDB didn't specify a program to run. Use the program from the
last run with the new argument list. */
- if (program_name == NULL)
+ if (program_path.get () == NULL)
{
write_enn (own_buf);
free_vector_argv (new_argv);
}
}
else
- {
- xfree (program_name);
- program_name = new_program_name;
- }
+ program_path.set (gdb::unique_xmalloc_ptr<char> (new_program_name));
/* Free the old argv and install the new one. */
free_vector_argv (program_args);
program_args = new_argv;
- create_inferior (program_name, program_args);
+ create_inferior (program_path.get (), program_args);
if (last_status.kind == TARGET_WAITKIND_STOPPED)
{
gdbserver_version (void)
{
printf ("GNU gdbserver %s%s\n"
- "Copyright (C) 2017 Free Software Foundation, Inc.\n"
+ "Copyright (C) 2018 Free Software Foundation, Inc.\n"
"gdbserver is free software, covered by the "
"GNU General Public License.\n"
"This gdbserver was configured as \"%s\"\n",
volatile int attach = 0;
int was_running;
bool selftest = false;
+#if GDB_SELF_TEST
const char *selftest_filter = NULL;
+#endif
+
+ current_directory = getcwd (NULL, 0);
+ if (current_directory == NULL)
+ {
+ error (_("Could not find current working directory: %s"),
+ safe_strerror (errno));
+ }
while (*next_arg != NULL && **next_arg == '-')
{
debug_threads = 1;
else if (startswith (*next_arg, "--debug-format="))
{
- char *error_msg
+ std::string error_msg
= parse_debug_format_options ((*next_arg)
+ sizeof ("--debug-format=") - 1, 0);
- if (error_msg != NULL)
+ if (!error_msg.empty ())
{
- fprintf (stderr, "%s", error_msg);
+ fprintf (stderr, "%s", error_msg.c_str ());
exit (1);
}
}
else if (startswith (*next_arg, "--selftest="))
{
selftest = true;
+#if GDB_SELF_TEST
selftest_filter = *next_arg + strlen ("--selftest=");
+#endif
}
else
{
opened by remote_prepare. */
notice_open_fds ();
- save_original_signals_state ();
+ save_original_signals_state (false);
/* We need to know whether the remote connection is stdio before
starting the inferior. Inferiors created in this scenario have
if (selftest)
{
+#if GDB_SELF_TEST
selftests::run_tests (selftest_filter);
+#else
+ printf (_("Selftests are not available in a non-development build.\n"));
+#endif
throw_quit ("Quit");
}
int i, n;
n = argc - (next_arg - argv);
- program_name = xstrdup (next_arg[0]);
+ program_path.set (gdb::unique_xmalloc_ptr<char> (xstrdup (next_arg[0])));
for (i = 1; i < n; i++)
program_args.push_back (xstrdup (next_arg[i]));
program_args.push_back (NULL);
/* Wait till we are at first instruction in program. */
- create_inferior (program_name, program_args);
+ create_inferior (program_path.get (), program_args);
/* We are now (hopefully) stopped at the first instruction of
the target process. This assumes that the target process was
fprintf (stderr, "GDBserver restarting\n");
/* Wait till we are at 1st instruction in prog. */
- if (program_name != NULL)
+ if (program_path.get () != NULL)
{
- create_inferior (program_name, program_args);
+ create_inferior (program_path.get (), program_args);
if (last_status.kind == TARGET_WAITKIND_STOPPED)
{