/* 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->entry.id,
- ¤t_btrace_conf);
- if (thread->btrace == NULL)
- return "E.Could not enable btrace.";
-
- return NULL;
+ thread->btrace = target_enable_btrace (thread->id, ¤t_btrace_conf);
}
/* 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->entry.id,
- ¤t_btrace_conf);
- if (thread->btrace == NULL)
- return "E.Could not enable btrace.";
-
- return NULL;
+ thread->btrace = target_enable_btrace (thread->id, ¤t_btrace_conf);
}
/* 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;
}
}
process = current_process ();
- VEC_truncate (int, process->syscalls_to_catch, 0);
+ process->syscalls_to_catch.clear ();
if (enabled)
{
while (*p != '\0')
{
p = decode_address_to_semicolon (&sysno, p);
- VEC_safe_push (int, process->syscalls_to_catch, (int) sysno);
+ process->syscalls_to_catch.push_back (sysno);
}
}
else
- VEC_safe_push (int, process->syscalls_to_catch, ANY_SYSCALL);
+ process->syscalls_to_catch.push_back (ANY_SYSCALL);
}
write_ok (own_buf);
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;
}
return;
}
+ if (startswith (own_buf, "QSetWorkingDir:"))
+ {
+ const char *p = own_buf + strlen ("QSetWorkingDir:");
+
+ if (*p != '\0')
+ {
+ std::string path = hex2str (p);
+
+ set_inferior_cwd (path.c_str ());
+
+ if (remote_debug)
+ debug_printf (_("[Set the inferior's current directory to %s]\n"),
+ path.c_str ());
+ }
+ else
+ {
+ /* An empty argument means that we should clear out any
+ previously set cwd for the inferior. */
+ set_inferior_cwd (NULL);
+
+ if (remote_debug)
+ debug_printf (_("\
+[Unset the inferior's current directory; will use gdbserver's cwd]\n"));
+ }
+ write_ok (own_buf);
+
+ return;
+ }
+
/* Otherwise we didn't know what packet it was. Say we didn't
understand it. */
own_buf[0] = 0;
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;
res = prepare_to_access_memory ();
if (res == 0)
{
- if (set_desired_thread (1))
+ if (set_desired_thread ())
res = read_inferior_memory (memaddr, myaddr, len);
else
res = 1;
ret = prepare_to_access_memory ();
if (ret == 0)
{
- if (set_desired_thread (1))
+ if (set_desired_thread ())
ret = write_inferior_memory (memaddr, myaddr, len);
else
ret = EIO;
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)
/* Handle qXfer:exec-file:read. */
static int
-handle_qxfer_exec_file (const char *const_annex,
+handle_qxfer_exec_file (const char *annex,
gdb_byte *readbuf, const gdb_byte *writebuf,
ULONGEST offset, LONGEST len)
{
if (the_target->pid_to_exec_file == NULL || writebuf != NULL)
return -2;
- if (const_annex[0] == '\0')
+ if (annex[0] == '\0')
{
if (current_thread == NULL)
return -1;
}
else
{
- char *annex = (char *) alloca (strlen (const_annex) + 1);
-
- strcpy (annex, const_annex);
annex = unpack_varlen_hex (annex, &pid);
-
if (annex[0] != '\0')
return -1;
}
return len;
}
-/* Worker routine for handle_qxfer_libraries.
- Add to the length pointed to by ARG a conservative estimate of the
- length needed to transmit the file name of INF. */
-
-static void
-accumulate_file_name_length (struct inferior_list_entry *inf, void *arg)
-{
- struct dll_info *dll = (struct dll_info *) inf;
- unsigned int *total_len = (unsigned int *) arg;
-
- /* Over-estimate the necessary memory. Assume that every character
- in the library name must be escaped. */
- *total_len += 128 + 6 * strlen (dll->name);
-}
-
-/* Worker routine for handle_qxfer_libraries.
- Emit the XML to describe the library in INF. */
-
-static void
-emit_dll_description (struct inferior_list_entry *inf, void *arg)
-{
- struct dll_info *dll = (struct dll_info *) inf;
- char **p_ptr = (char **) arg;
- char *p = *p_ptr;
-
- strcpy (p, " <library name=\"");
- p = p + strlen (p);
- std::string name = xml_escape_text (dll->name);
- strcpy (p, name.c_str ());
- p = p + strlen (p);
- strcpy (p, "\"><segment address=\"");
- p = p + strlen (p);
- sprintf (p, "0x%lx", (long) dll->base_addr);
- p = p + strlen (p);
- strcpy (p, "\"/></library>\n");
- p = p + strlen (p);
-
- *p_ptr = p;
-}
-
/* Handle qXfer:libraries:read. */
static int
gdb_byte *readbuf, const gdb_byte *writebuf,
ULONGEST offset, LONGEST len)
{
- unsigned int total_len;
- char *document, *p;
-
if (writebuf != NULL)
return -2;
if (annex[0] != '\0' || current_thread == NULL)
return -1;
- total_len = 64;
- for_each_inferior_with_data (&all_dlls, accumulate_file_name_length,
- &total_len);
-
- document = (char *) malloc (total_len);
- if (document == NULL)
- return -1;
-
- strcpy (document, "<library-list version=\"1.0\">\n");
- p = document + strlen (document);
+ std::string document = "<library-list version=\"1.0\">\n";
- for_each_inferior_with_data (&all_dlls, emit_dll_description, &p);
+ for (const dll_info &dll : all_dlls)
+ document += string_printf
+ (" <library name=\"%s\"><segment address=\"0x%lx\"/></library>\n",
+ dll.name.c_str (), (long) dll.base_addr);
- strcpy (p, "</library-list>\n");
+ document += "</library-list>\n";
- total_len = strlen (document);
+ if (offset > document.length ())
+ return -1;
- if (offset > total_len)
- {
- free (document);
- return -1;
- }
+ if (offset + len > document.length ())
+ len = document.length () - offset;
- if (offset + len > total_len)
- len = total_len - offset;
+ memcpy (readbuf, &document[offset], len);
- memcpy (readbuf, document + offset, len);
- free (document);
return len;
}
Emit the XML to describe the thread of INF. */
static void
-handle_qxfer_threads_worker (struct inferior_list_entry *inf, void *arg)
+handle_qxfer_threads_worker (thread_info *thread, struct buffer *buffer)
{
- struct thread_info *thread = (struct thread_info *) inf;
- struct buffer *buffer = (struct buffer *) arg;
ptid_t ptid = ptid_of (thread);
char ptid_s[100];
int core = target_core_of_thread (ptid);
char core_s[21];
const char *name = target_thread_name (ptid);
+ int handle_len;
+ gdb_byte *handle;
+ bool handle_status = target_thread_handle (ptid, &handle, &handle_len);
write_ptid (ptid_s, ptid);
if (name != NULL)
buffer_xml_printf (buffer, " name=\"%s\"", name);
+ if (handle_status)
+ {
+ char *handle_s = (char *) alloca (handle_len * 2 + 1);
+ bin2hex (handle, handle_s, handle_len);
+ buffer_xml_printf (buffer, " handle=\"%s\"", handle_s);
+ }
+
buffer_xml_printf (buffer, "/>\n");
}
{
buffer_grow_str (buffer, "<threads>\n");
- for_each_inferior_with_data (&all_threads, handle_qxfer_threads_worker,
- buffer);
+ for_each_thread ([&] (thread_info *thread)
+ {
+ handle_qxfer_threads_worker (thread, buffer);
+ });
buffer_grow_str0 (buffer, "</threads>\n");
}
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+");
static void
handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
{
- static struct inferior_list_entry *thread_ptr;
+ static std::list<thread_info *>::const_iterator thread_iter;
/* Reply the current thread id. */
if (strcmp ("qC", own_buf) == 0 && !disable_packet_qC)
ptid = general_thread;
else
{
- thread_ptr = get_first_inferior (&all_threads);
- ptid = thread_ptr->id;
+ thread_iter = all_threads.begin ();
+ ptid = (*thread_iter)->id;
}
sprintf (own_buf, "QC");
if (strcmp ("qfThreadInfo", own_buf) == 0)
{
require_running_or_return (own_buf);
- thread_ptr = get_first_inferior (&all_threads);
+ thread_iter = all_threads.begin ();
*own_buf++ = 'm';
- write_ptid (own_buf, thread_ptr->id);
- thread_ptr = thread_ptr->next;
+ ptid_t ptid = (*thread_iter)->id;
+ write_ptid (own_buf, ptid);
+ thread_iter++;
return;
}
if (strcmp ("qsThreadInfo", own_buf) == 0)
{
require_running_or_return (own_buf);
- if (thread_ptr != NULL)
+ if (thread_iter != all_threads.end ())
{
*own_buf++ = 'm';
- write_ptid (own_buf, thread_ptr->id);
- thread_ptr = thread_ptr->next;
+ ptid_t ptid = (*thread_iter)->id;
+ write_ptid (own_buf, ptid);
+ thread_iter++;
return;
}
else
sprintf (own_buf,
"PacketSize=%x;QPassSignals+;QProgramSignals+;"
"QStartupWithShell+;QEnvironmentHexEncoded+;"
- "QEnvironmentReset+;QEnvironmentUnset+",
+ "QEnvironmentReset+;QEnvironmentUnset+;"
+ "QSetWorkingDir+",
PBUFSIZ - 1);
if (target_supports_catch_syscall ())
if (the_target->get_tib_address != NULL
&& startswith (own_buf, "qGetTIBAddr:"))
{
- char *annex;
+ const char *annex;
int n;
CORE_ADDR tlb;
ptid_t ptid = read_ptid (own_buf + 12, &annex);
if (own_buf[sizeof ("qAttached") - 1])
{
int pid = strtoul (own_buf + sizeof ("qAttached:") - 1, NULL, 16);
- process = (struct process_info *)
- find_inferior_id (&all_processes, pid_to_ptid (pid));
+ process = find_process_pid (pid);
}
else
{
if (startswith (own_buf, "qCRC:"))
{
/* CRC check (compare-section). */
- char *comma;
+ const char *comma;
ULONGEST base;
int len;
unsigned long long crc;
typedef int (visit_actioned_threads_callback_ftype)
(const struct thread_resume *, struct thread_info *);
-/* Struct to pass data to visit_actioned_threads. */
-
-struct visit_actioned_threads_data
-{
- const struct thread_resume *actions;
- size_t num_actions;
- visit_actioned_threads_callback_ftype *callback;
-};
-
/* Call CALLBACK for any thread to which ACTIONS applies to. Returns
true if CALLBACK returns true. Returns false if no matching thread
is found or CALLBACK results false.
- Note: This function is itself a callback for find_inferior. */
+ Note: This function is itself a callback for find_thread. */
-static int
-visit_actioned_threads (struct inferior_list_entry *entry, void *datap)
+static bool
+visit_actioned_threads (thread_info *thread,
+ const struct thread_resume *actions,
+ size_t num_actions,
+ visit_actioned_threads_callback_ftype *callback)
{
- struct visit_actioned_threads_data *data
- = (struct visit_actioned_threads_data *) datap;
- const struct thread_resume *actions = data->actions;
- size_t num_actions = data->num_actions;
- visit_actioned_threads_callback_ftype *callback = data->callback;
- size_t i;
-
- for (i = 0; i < num_actions; i++)
+ for (size_t i = 0; i < num_actions; i++)
{
const struct thread_resume *action = &actions[i];
if (ptid_equal (action->thread, minus_one_ptid)
- || ptid_equal (action->thread, entry->id)
+ || ptid_equal (action->thread, thread->id)
|| ((ptid_get_pid (action->thread)
- == ptid_get_pid (entry->id))
+ == thread->id.pid ())
&& ptid_get_lwp (action->thread) == -1))
{
- struct thread_info *thread = (struct thread_info *) entry;
-
if ((*callback) (action, thread))
- return 1;
+ return true;
}
}
- return 0;
+ return false;
}
/* Callback for visit_actioned_threads. If the thread has a pending
thread->status_pending_p = 0;
last_status = thread->last_status;
- last_ptid = thread->entry.id;
+ last_ptid = thread->id;
prepare_resume_reply (own_buf, last_ptid, &last_status);
return 1;
}
static void
handle_v_cont (char *own_buf)
{
- char *p, *q;
+ const char *p;
int n = 0, i = 0;
struct thread_resume *resume_info;
struct thread_resume default_action { null_ptid };
if (p[0] == 'S' || p[0] == 'C')
{
- int sig;
- sig = strtol (p + 1, &q, 16);
+ char *q;
+ int sig = strtol (p + 1, &q, 16);
if (p == q)
goto err;
p = q;
}
else if (p[0] == ':')
{
+ const char *q;
ptid_t ptid = read_ptid (p + 1, &q);
if (p == q)
one with a pending status to report. If so, skip actually
resuming/stopping and report the pending event
immediately. */
- struct visit_actioned_threads_data data;
- data.actions = actions;
- data.num_actions = num_actions;
- data.callback = handle_pending_status;
- if (find_inferior (&all_threads, visit_actioned_threads, &data) != NULL)
+ thread_info *thread_with_status = find_thread ([&] (thread_info *thread)
+ {
+ return visit_actioned_threads (thread, actions, num_actions,
+ handle_pending_status);
+ });
+
+ if (thread_with_status != NULL)
return;
enable_async_io ();
{
/* 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)
{
resume (resume_info, n);
}
-/* Callback for for_each_inferior. Make a new stop reply for each
+/* Callback for for_each_thread. Make a new stop reply for each
stopped thread. */
-static int
-queue_stop_reply_callback (struct inferior_list_entry *entry, void *arg)
+static void
+queue_stop_reply_callback (thread_info *thread)
{
- struct thread_info *thread = (struct thread_info *) entry;
-
/* For now, assume targets that don't have this callback also don't
manage the thread's last_status field. */
if (the_target->thread_stopped == NULL)
{
struct vstop_notif *new_notif = XNEW (struct vstop_notif);
- new_notif->ptid = entry->id;
+ new_notif->ptid = thread->id;
new_notif->status = thread->last_status;
/* Pass the last stop reply back to GDB, but don't notify
yet. */
= target_waitstatus_to_string (&thread->last_status);
debug_printf ("Reporting thread %s as already stopped with %s\n",
- target_pid_to_str (entry->id),
+ target_pid_to_str (thread->id),
status_string.c_str ());
}
/* Pass the last stop reply back to GDB, but don't notify
yet. */
- queue_stop_reply (entry->id, &thread->last_status);
+ queue_stop_reply (thread->id, &thread->last_status);
}
}
-
- return 0;
}
/* Set this inferior threads's state as "want-stopped". We won't
it. */
static void
-gdb_wants_thread_stopped (struct inferior_list_entry *entry)
+gdb_wants_thread_stopped (thread_info *thread)
{
- struct thread_info *thread = (struct thread_info *) entry;
-
thread->last_resume_kind = resume_stop;
if (thread->last_status.kind == TARGET_WAITKIND_IGNORE)
static void
gdb_wants_all_threads_stopped (void)
{
- for_each_inferior (&all_threads, gdb_wants_thread_stopped);
-}
-
-/* Clear the gdb_detached flag of every process. */
-
-static void
-gdb_reattached_process (struct inferior_list_entry *entry)
-{
- struct process_info *process = (struct process_info *) entry;
-
- process->gdb_detached = 0;
-}
-
-/* Callback for for_each_inferior. Clear the thread's pending status
- flag. */
-
-static void
-clear_pending_status_callback (struct inferior_list_entry *entry)
-{
- struct thread_info *thread = (struct thread_info *) entry;
-
- thread->status_pending_p = 0;
+ for_each_thread (gdb_wants_thread_stopped);
}
-/* Callback for for_each_inferior. If the thread is stopped with an
+/* Callback for for_each_thread. If the thread is stopped with an
interesting event, mark it as having a pending event. */
static void
-set_pending_status_callback (struct inferior_list_entry *entry)
+set_pending_status_callback (thread_info *thread)
{
- struct thread_info *thread = (struct thread_info *) entry;
-
if (thread->last_status.kind != TARGET_WAITKIND_STOPPED
|| (thread->last_status.value.sig != GDB_SIGNAL_0
/* A breakpoint, watchpoint or finished step from a previous
thread->status_pending_p = 1;
}
-/* Callback for find_inferior. Return true if ENTRY (a thread) has a
- pending status to report to GDB. */
-
-static int
-find_status_pending_thread_callback (struct inferior_list_entry *entry, void *data)
-{
- struct thread_info *thread = (struct thread_info *) entry;
-
- return thread->status_pending_p;
-}
-
/* Status handler for the '?' packet. */
static void
handle_status (char *own_buf)
{
/* GDB is connected, don't forward events to the target anymore. */
- for_each_inferior (&all_processes, gdb_reattached_process);
+ for_each_process ([] (process_info *process) {
+ process->gdb_detached = 0;
+ });
/* In non-stop mode, we must send a stop reply for each stopped
thread. In all-stop mode, just send one for the first stopped
if (non_stop)
{
- find_inferior (&all_threads, queue_stop_reply_callback, NULL);
+ for_each_thread (queue_stop_reply_callback);
/* The first is sent immediatly. OK is sent if there is no
stopped thread, which is the same handling of the vStopped
}
else
{
- struct inferior_list_entry *thread = NULL;
+ thread_info *thread = NULL;
pause_all (0);
stabilize_threads ();
reporting now pending. They'll be reported the next time the
threads are resumed. Start by marking all interesting events
as pending. */
- for_each_inferior (&all_threads, set_pending_status_callback);
+ for_each_thread (set_pending_status_callback);
/* Prefer the last thread that reported an event to GDB (even if
that was a GDB_SIGNAL_TRAP). */
if (last_status.kind != TARGET_WAITKIND_IGNORE
&& last_status.kind != TARGET_WAITKIND_EXITED
&& last_status.kind != TARGET_WAITKIND_SIGNALLED)
- thread = find_inferior_id (&all_threads, last_ptid);
+ thread = find_thread_ptid (last_ptid);
/* If the last event thread is not found for some reason, look
for some other thread that might have an event to report. */
if (thread == NULL)
- thread = find_inferior (&all_threads,
- find_status_pending_thread_callback, NULL);
+ thread = find_thread ([] (thread_info *thread)
+ {
+ return thread->status_pending_p;
+ });
/* If we're still out of luck, simply pick the first thread in
the thread list. */
if (thread == NULL)
- thread = get_first_inferior (&all_threads);
+ thread = get_first_thread ();
if (thread != NULL)
{
/* GDB assumes the current thread is the thread we're
reporting the status for. */
general_thread = thread->id;
- set_desired_thread (1);
+ set_desired_thread ();
gdb_assert (tp->last_status.kind != TARGET_WAITKIND_IGNORE);
- prepare_resume_reply (own_buf, tp->entry.id, &tp->last_status);
+ prepare_resume_reply (own_buf, tp->id, &tp->last_status);
}
else
strcpy (own_buf, "W00");
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",
}
static void
-kill_inferior_callback (struct inferior_list_entry *entry)
+kill_inferior_callback (process_info *process)
{
- struct process_info *process = (struct process_info *) entry;
- int pid = ptid_get_pid (process->entry.id);
+ int pid = process->pid;
kill_inferior (pid);
discard_queued_stop_replies (pid_to_ptid (pid));
}
-/* Callback for for_each_inferior to detach or kill the inferior,
- depending on whether we attached to it or not.
- We inform the user whether we're detaching or killing the process
- as this is only called when gdbserver is about to exit. */
-
-static void
-detach_or_kill_inferior_callback (struct inferior_list_entry *entry)
-{
- struct process_info *process = (struct process_info *) entry;
- int pid = ptid_get_pid (process->entry.id);
-
- if (process->attached)
- detach_inferior (pid);
- else
- kill_inferior (pid);
-
- discard_queued_stop_replies (pid_to_ptid (pid));
-}
-
-/* for_each_inferior callback for detach_or_kill_for_exit to print
- the pids of started inferiors. */
-
-static void
-print_started_pid (struct inferior_list_entry *entry)
-{
- struct process_info *process = (struct process_info *) entry;
-
- if (! process->attached)
- {
- int pid = ptid_get_pid (process->entry.id);
- fprintf (stderr, " %d", pid);
- }
-}
-
-/* for_each_inferior callback for detach_or_kill_for_exit to print
- the pids of attached inferiors. */
-
-static void
-print_attached_pid (struct inferior_list_entry *entry)
-{
- struct process_info *process = (struct process_info *) entry;
-
- if (process->attached)
- {
- int pid = ptid_get_pid (process->entry.id);
- fprintf (stderr, " %d", pid);
- }
-}
-
/* Call this when exiting gdbserver with possible inferiors that need
to be killed or detached from. */
if (have_started_inferiors_p ())
{
fprintf (stderr, "Killing process(es):");
- for_each_inferior (&all_processes, print_started_pid);
+
+ for_each_process ([] (process_info *process) {
+ if (!process->attached)
+ fprintf (stderr, " %d", process->pid);
+ });
+
fprintf (stderr, "\n");
}
if (have_attached_inferiors_p ())
{
fprintf (stderr, "Detaching process(es):");
- for_each_inferior (&all_processes, print_attached_pid);
+
+ for_each_process ([] (process_info *process) {
+ if (process->attached)
+ fprintf (stderr, " %d", process->pid);
+ });
+
fprintf (stderr, "\n");
}
/* Now we can kill or detach the inferiors. */
+ for_each_process ([] (process_info *process) {
+ int pid = process->pid;
+
+ if (process->attached)
+ detach_inferior (pid);
+ else
+ kill_inferior (pid);
- for_each_inferior (&all_processes, detach_or_kill_inferior_callback);
+ discard_queued_stop_replies (pid_to_ptid (pid));
+ });
}
/* Value that will be passed to exit(3) when gdbserver exits. */
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
(by the same GDB instance or another) will refresh all its
state from scratch. */
discard_queued_stop_replies (minus_one_ptid);
- for_each_inferior (&all_threads,
- clear_pending_status_callback);
+ for_each_thread ([] (thread_info *thread)
+ {
+ thread->status_pending_p = 0;
+ });
if (tracing)
{
after the last processed option. */
static void
-process_point_options (struct gdb_breakpoint *bp, char **packet)
+process_point_options (struct gdb_breakpoint *bp, const char **packet)
{
- char *dataptr = *packet;
+ const char *dataptr = *packet;
int persist;
/* Check if data has the correct format. */
break;
}
- thread_id = thread->entry.id;
+ thread_id = thread->id;
}
else
{
/* GDB is telling us to choose any thread. Check if
the currently selected thread is still valid. If
it is not, select the first available. */
- struct thread_info *thread =
- (struct thread_info *) find_inferior_id (&all_threads,
- general_thread);
+ thread_info *thread = find_thread_ptid (general_thread);
if (thread == NULL)
thread = get_first_thread ();
- thread_id = thread->entry.id;
+ thread_id = thread->id;
}
general_thread = thread_id;
- set_desired_thread (1);
+ set_desired_thread ();
gdb_assert (current_thread != NULL);
}
else if (own_buf[1] == 'c')
{
struct regcache *regcache;
- if (!set_desired_thread (1))
+ if (!set_desired_thread ())
write_enn (own_buf);
else
{
{
struct regcache *regcache;
- if (!set_desired_thread (1))
+ if (!set_desired_thread ())
write_enn (own_buf);
else
{
char type = own_buf[1];
int res;
const int insert = ch == 'Z';
- char *p = &own_buf[3];
+ const char *p = &own_buf[3];
p = unpack_varlen_hex (p, &addr);
kind = strtol (p + 1, &dataptr, 16);
is telling us to drop that list and use this one
instead. */
clear_breakpoint_conditions_and_commands (bp);
- process_point_options (bp, &dataptr);
+ const char *options = dataptr;
+ process_point_options (bp, &options);
}
}
else
return 0;
fprintf (stderr, "Killing all inferiors\n");
- for_each_inferior (&all_processes, kill_inferior_callback);
+
+ for_each_process (kill_inferior_callback);
/* When using the extended protocol, we wait with no program
running. The traditional protocol will exit instead. */
if (extended_protocol)
{
if (target_running ())
- for_each_inferior (&all_processes,
- kill_inferior_callback);
+ for_each_process (kill_inferior_callback);
+
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)
{
/* Be sure to not change the selected thread behind GDB's back.
Important in the non-stop mode asynchronous protocol. */
- set_desired_thread (1);
+ set_desired_thread ();
return 0;
}
/* Be sure to not change the selected thread behind GDB's back.
Important in the non-stop mode asynchronous protocol. */
- set_desired_thread (1);
+ set_desired_thread ();
return 0;
}