/* Main code for remote server for GDB.
- Copyright (C) 1989-2013 Free Software Foundation, Inc.
+ Copyright (C) 1989-2014 Free Software Foundation, Inc.
This file is part of GDB.
#include "agent.h"
#include "notif.h"
#include "tdesc.h"
+#include "rsp-low.h"
+#include <ctype.h>
#include <unistd.h>
#if HAVE_SIGNAL_H
#include <signal.h>
#endif
+#include "gdb_vecs.h"
#include "gdb_wait.h"
#include "btrace-common.h"
+#include "filestuff.h"
+#include "tracepoint.h"
+#include "dll.h"
+#include "hostio.h"
/* The thread set with an `Hc' packet. `Hc' is deprecated in favor of
`vCont'. Note the multi-process extensions made `vCont' a
static char **program_argv, **wrapper_argv;
-/* Enable miscellaneous debugging output. The name is historical - it
- was originally used to debug LinuxThreads support. */
-int debug_threads;
-
/* Enable debugging of h/w breakpoint/watchpoint support. */
int debug_hw_points;
static int
target_running (void)
{
- return all_threads.head != NULL;
+ return get_first_thread () != NULL;
}
static int
{
int i;
for (i = 0; new_argv[i]; ++i)
- fprintf (stderr, "new_argv[%d] = \"%s\"\n", i, new_argv[i]);
- fflush (stderr);
+ debug_printf ("new_argv[%d] = \"%s\"\n", i, new_argv[i]);
+ debug_flush ();
}
#ifdef SIGTTOU
{
struct thread_resume resume_info;
+ memset (&resume_info, 0, sizeof (resume_info));
resume_info.thread = pid_to_ptid (signal_pid);
resume_info.kind = resume_continue;
resume_info.sig = 0;
monitor_output (" Enable h/w breakpoint/watchpoint debugging messages\n");
monitor_output (" set remote-debug <0|1>\n");
monitor_output (" Enable remote protocol debugging messages\n");
+ monitor_output (" set debug-format option1[,option2,...]\n");
+ monitor_output (" Add additional information to debugging messages\n");
+ monitor_output (" Options: all, none");
+#ifdef HAVE_GETTIMEOFDAY
+ monitor_output (", timestamp");
+#endif
+ monitor_output ("\n");
monitor_output (" exit\n");
monitor_output (" Quit GDBserver\n");
}
if (traceframe_read_mem (current_traceframe,
memaddr, myaddr, len, &nbytes))
- return EIO;
+ return -1;
/* Data read from trace buffer, we're done. */
if (nbytes > 0)
return nbytes;
return; \
}
+/* Parse options to --debug-format= and "monitor set debug-format".
+ 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.
+
+ N.B. These commands affect all debug format settings, they are not
+ cumulative. If a format is not specified, it is turned off.
+ However, we don't go to extra trouble with things like
+ "monitor set debug-format all,none,timestamp".
+ Instead we just parse them one at a time, in order.
+
+ The syntax for "monitor set debug" we support here is not identical
+ to gdb's "set debug foo on|off" because we also use this function to
+ parse "--debug-format=foo,bar". */
+
+static char *
+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;
+
+ /* First remove leading spaces, for "monitor set debug-format". */
+ while (isspace (*arg))
+ ++arg;
+
+ options = delim_string_to_char_ptr_vec (arg, ',');
+
+ for (ix = 0; VEC_iterate (char_ptr, options, ix, option); ++ix)
+ {
+ if (strcmp (option, "all") == 0)
+ {
+ debug_timestamp = 1;
+ if (is_monitor)
+ monitor_output ("All extra debug format options enabled.\n");
+ }
+ else if (strcmp (option, "none") == 0)
+ {
+ debug_timestamp = 0;
+ if (is_monitor)
+ monitor_output ("All extra debug format options disabled.\n");
+ }
+#ifdef HAVE_GETTIMEOFDAY
+ else if (strcmp (option, "timestamp") == 0)
+ {
+ debug_timestamp = 1;
+ if (is_monitor)
+ monitor_output ("Timestamps will be added to debug output.\n");
+ }
+#endif
+ else if (*option == '\0')
+ {
+ /* An empty option, e.g., "--debug-format=foo,,bar", is ignored. */
+ continue;
+ }
+ else
+ {
+ char *msg = xstrprintf ("Unknown debug-format argument: \"%s\"\n",
+ option);
+
+ free_char_ptr_vec (options);
+ return msg;
+ }
+ }
+
+ free_char_ptr_vec (options);
+ return NULL;
+}
+
/* Handle monitor commands not handled by target-specific handlers. */
static void
remote_debug = 0;
monitor_output ("Protocol debug output disabled.\n");
}
+ else if (strncmp (mon, "set debug-format ",
+ sizeof ("set debug-format ") - 1) == 0)
+ {
+ char *error_msg
+ = parse_debug_format_options (mon + sizeof ("set debug-format ") - 1,
+ 1);
+
+ if (error_msg != NULL)
+ {
+ monitor_output (error_msg);
+ monitor_show_help ();
+ write_enn (own_buf);
+ xfree (error_msg);
+ }
+ }
else if (strcmp (mon, "help") == 0)
monitor_show_help ();
else if (strcmp (mon, "exit") == 0)
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 = 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 = arg;
+ char *p = *p_ptr;
+ char *name;
+
+ strcpy (p, " <library name=\"");
+ p = p + strlen (p);
+ name = xml_escape_text (dll->name);
+ strcpy (p, name);
+ free (name);
+ 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
{
unsigned int total_len;
char *document, *p;
- struct inferior_list_entry *dll_ptr;
if (writebuf != NULL)
return -2;
if (annex[0] != '\0' || !target_running ())
return -1;
- /* Over-estimate the necessary memory. Assume that every character
- in the library name must be escaped. */
total_len = 64;
- for (dll_ptr = all_dlls.head; dll_ptr != NULL; dll_ptr = dll_ptr->next)
- total_len += 128 + 6 * strlen (((struct dll_info *) dll_ptr)->name);
+ for_each_inferior_with_data (&all_dlls, accumulate_file_name_length,
+ &total_len);
document = malloc (total_len);
if (document == NULL)
strcpy (document, "<library-list>\n");
p = document + strlen (document);
- for (dll_ptr = all_dlls.head; dll_ptr != NULL; dll_ptr = dll_ptr->next)
- {
- struct dll_info *dll = (struct dll_info *) dll_ptr;
- char *name;
-
- strcpy (p, " <library name=\"");
- p = p + strlen (p);
- name = xml_escape_text (dll->name);
- strcpy (p, name);
- free (name);
- 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);
- }
+ for_each_inferior_with_data (&all_dlls, emit_dll_description, &p);
strcpy (p, "</library-list>\n");
return nbytes;
}
-/* Helper for handle_qxfer_threads. */
+/* Helper for handle_qxfer_threads_proper.
+ Emit the XML to describe the thread of INF. */
static void
-handle_qxfer_threads_proper (struct buffer *buffer)
+handle_qxfer_threads_worker (struct inferior_list_entry *inf, void *arg)
{
- struct inferior_list_entry *thread;
+ struct thread_info *thread = (struct thread_info *) inf;
+ struct buffer *buffer = arg;
+ ptid_t ptid = thread_to_gdb_id (thread);
+ char ptid_s[100];
+ int core = target_core_of_thread (ptid);
+ char core_s[21];
- buffer_grow_str (buffer, "<threads>\n");
+ write_ptid (ptid_s, ptid);
- for (thread = all_threads.head; thread; thread = thread->next)
+ if (core != -1)
{
- ptid_t ptid = thread_to_gdb_id ((struct thread_info *)thread);
- char ptid_s[100];
- int core = target_core_of_thread (ptid);
- char core_s[21];
+ sprintf (core_s, "%d", core);
+ buffer_xml_printf (buffer, "<thread id=\"%s\" core=\"%s\"/>\n",
+ ptid_s, core_s);
+ }
+ else
+ {
+ buffer_xml_printf (buffer, "<thread id=\"%s\"/>\n",
+ ptid_s);
+ }
+}
- write_ptid (ptid_s, ptid);
+/* Helper for handle_qxfer_threads. */
- if (core != -1)
- {
- sprintf (core_s, "%d", core);
- buffer_xml_printf (buffer, "<thread id=\"%s\" core=\"%s\"/>\n",
- ptid_s, core_s);
- }
- else
- {
- buffer_xml_printf (buffer, "<thread id=\"%s\"/>\n",
- ptid_s);
- }
- }
+static void
+handle_qxfer_threads_proper (struct buffer *buffer)
+{
+ buffer_grow_str (buffer, "<threads>\n");
+
+ for_each_inferior_with_data (&all_threads, handle_qxfer_threads_worker,
+ buffer);
buffer_grow_str0 (buffer, "</threads>\n");
}
{
static struct buffer cache;
struct thread_info *thread;
- int type;
+ int type, result;
if (the_target->read_btrace == NULL || writebuf != NULL)
return -2;
}
if (strcmp (annex, "all") == 0)
- type = btrace_read_all;
+ type = BTRACE_READ_ALL;
else if (strcmp (annex, "new") == 0)
- type = btrace_read_new;
+ type = BTRACE_READ_NEW;
+ else if (strcmp (annex, "delta") == 0)
+ type = BTRACE_READ_DELTA;
else
{
strcpy (own_buf, "E.Bad annex.");
{
buffer_free (&cache);
- target_read_btrace (thread->btrace, &cache, type);
+ result = target_read_btrace (thread->btrace, &cache, type);
+ if (result != 0)
+ {
+ memcpy (own_buf, cache.buffer, cache.used_size);
+ return -3;
+ }
}
else if (offset > cache.used_size)
{
gdb_id = general_thread;
else
{
- thread_ptr = all_threads.head;
+ thread_ptr = get_first_inferior (&all_threads);
gdb_id = thread_to_gdb_id ((struct thread_info *)thread_ptr);
}
ptid_t gdb_id;
require_running (own_buf);
- thread_ptr = all_threads.head;
+ thread_ptr = get_first_inferior (&all_threads);
*own_buf++ = 'm';
gdb_id = thread_to_gdb_id ((struct thread_info *)thread_ptr);
return;
}
- if ((len % 2) != 0 || unhexify (mon, own_buf + 6, len / 2) != len / 2)
+ if ((len % 2) != 0
+ || hex2bin (own_buf + 6, (gdb_byte *) mon, len / 2) != len / 2)
{
write_enn (own_buf);
free (mon);
}
static void gdb_wants_all_threads_stopped (void);
+static void resume (struct thread_resume *actions, size_t n);
+
+/* The callback that is passed to visit_actioned_threads. */
+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. */
+
+static int
+visit_actioned_threads (struct inferior_list_entry *entry, void *datap)
+{
+ struct visit_actioned_threads_data *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++)
+ {
+ const struct thread_resume *action = &actions[i];
+
+ if (ptid_equal (action->thread, minus_one_ptid)
+ || ptid_equal (action->thread, entry->id)
+ || ((ptid_get_pid (action->thread)
+ == ptid_get_pid (entry->id))
+ && ptid_get_lwp (action->thread) == -1))
+ {
+ struct thread_info *thread = (struct thread_info *) entry;
+
+ if ((*callback) (action, thread))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Callback for visit_actioned_threads. If the thread has a pending
+ status to report, report it now. */
+
+static int
+handle_pending_status (const struct thread_resume *resumption,
+ struct thread_info *thread)
+{
+ if (thread->status_pending_p)
+ {
+ thread->status_pending_p = 0;
+
+ last_status = thread->last_status;
+ last_ptid = thread->entry.id;
+ prepare_resume_reply (own_buf, last_ptid, &last_status);
+ return 1;
+ }
+ return 0;
+}
/* Parse vCont packets. */
void
cont_thread = minus_one_ptid;
set_desired_inferior (0);
+ resume (resume_info, n);
+ free (resume_info);
+ return;
+
+err:
+ write_enn (own_buf);
+ free (resume_info);
+ return;
+}
+
+/* Resume target with ACTIONS, an array of NUM_ACTIONS elements. */
+
+static void
+resume (struct thread_resume *actions, size_t num_actions)
+{
if (!non_stop)
- enable_async_io ();
+ {
+ /* Check if among the threads that GDB wants actioned, there's
+ 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;
- (*the_target->resume) (resume_info, n);
+ data.actions = actions;
+ data.num_actions = num_actions;
+ data.callback = handle_pending_status;
+ if (find_inferior (&all_threads, visit_actioned_threads, &data) != NULL)
+ return;
- free (resume_info);
+ enable_async_io ();
+ }
+
+ (*the_target->resume) (actions, num_actions);
if (non_stop)
write_ok (own_buf);
{
last_ptid = mywait (minus_one_ptid, &last_status, 0, 1);
+ if (last_status.kind == TARGET_WAITKIND_NO_RESUMED)
+ {
+ /* No proper RSP support for this yet. At least return
+ error. */
+ sprintf (own_buf, "E.No unwaited-for children left.");
+ disable_async_io ();
+ return;
+ }
+
if (last_status.kind != TARGET_WAITKIND_EXITED
- && last_status.kind != TARGET_WAITKIND_SIGNALLED)
+ && last_status.kind != TARGET_WAITKIND_SIGNALLED
+ && last_status.kind != TARGET_WAITKIND_NO_RESUMED)
current_inferior->last_status = last_status;
/* From the client's perspective, all-stop mode always stops all
|| last_status.kind == TARGET_WAITKIND_SIGNALLED)
mourn_inferior (find_process_pid (ptid_get_pid (last_ptid)));
}
- return;
-
-err:
- write_enn (own_buf);
- free (resume_info);
- return;
}
/* Attach to a new program. Return 1 if successful, 0 if failure. */
{
/* FIXME: Fail request if out of memory instead of dying. */
new_argv[i] = xmalloc (1 + (next_p - p) / 2);
- unhexify (new_argv[i], p, (next_p - p) / 2);
+ hex2bin (p, (gdb_byte *) new_argv[i], (next_p - p) / 2);
new_argv[i][(next_p - p) / 2] = '\0';
}
n++;
}
- if (!non_stop)
- enable_async_io ();
-
- (*the_target->resume) (resume_info, n);
-
- if (non_stop)
- write_ok (own_buf);
- else
- {
- last_ptid = mywait (minus_one_ptid, &last_status, 0, 1);
-
- if (last_status.kind != TARGET_WAITKIND_EXITED
- && last_status.kind != TARGET_WAITKIND_SIGNALLED)
- {
- current_inferior->last_resume_kind = resume_stop;
- current_inferior->last_status = last_status;
- }
-
- prepare_resume_reply (own_buf, last_ptid, &last_status);
- disable_async_io ();
-
- if (last_status.kind == TARGET_WAITKIND_EXITED
- || last_status.kind == TARGET_WAITKIND_SIGNALLED)
- mourn_inferior (find_process_pid (ptid_get_pid (last_ptid)));
- }
+ resume (resume_info, n);
}
/* Callback for for_each_inferior. Make a new stop reply for each
char *status_string
= target_waitstatus_to_string (&thread->last_status);
- fprintf (stderr,
- "Reporting thread %s as already stopped with %s\n",
- target_pid_to_str (entry->id),
- status_string);
+ debug_printf ("Reporting thread %s as already stopped with %s\n",
+ target_pid_to_str (entry->id),
+ status_string);
xfree (status_string);
}
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;
+}
+
+/* Callback for for_each_inferior. 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)
+{
+ 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
+ GDB run isn't considered interesting for a new GDB run.
+ If we left those pending, the new GDB could consider them
+ random SIGTRAPs. This leaves out real async traps. We'd
+ have to peek into the (target-specific) siginfo to
+ distinguish those. */
+ && thread->last_status.value.sig != GDB_SIGNAL_TRAP))
+ 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
if (non_stop)
{
- discard_queued_stop_replies (-1);
find_inferior (&all_threads, queue_stop_reply_callback, NULL);
/* The first is sent immediatly. OK is sent if there is no
}
else
{
+ struct inferior_list_entry *thread = NULL;
+
pause_all (0);
stabilize_threads ();
gdb_wants_all_threads_stopped ();
- if (all_threads.head)
- {
- struct target_waitstatus status;
+ /* We can only report one status, but we might be coming out of
+ non-stop -- if more than one thread is stopped with
+ interesting events, leave events for the threads we're not
+ 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);
+
+ /* 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);
+
+ /* 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);
+
+ /* 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);
+
+ if (thread != NULL)
+ {
+ struct thread_info *tp = (struct thread_info *) thread;
+
+ /* We're reporting this event, so it's no longer
+ pending. */
+ tp->status_pending_p = 0;
+
+ /* GDB assumes the current thread is the thread we're
+ reporting the status for. */
+ general_thread = thread->id;
+ set_desired_inferior (1);
- status.kind = TARGET_WAITKIND_STOPPED;
- status.value.sig = GDB_SIGNAL_TRAP;
- prepare_resume_reply (own_buf,
- all_threads.head->id, &status);
+ gdb_assert (tp->last_status.kind != TARGET_WAITKIND_IGNORE);
+ prepare_resume_reply (own_buf, tp->entry.id, &tp->last_status);
}
else
strcpy (own_buf, "W00");
gdbserver_version (void)
{
printf ("GNU gdbserver %s%s\n"
- "Copyright (C) 2013 Free Software Foundation, Inc.\n"
+ "Copyright (C) 2014 Free Software Foundation, Inc.\n"
"gdbserver is free software, covered by the "
"GNU General Public License.\n"
"This gdbserver was configured as \"%s\"\n",
"\n"
"Options:\n"
" --debug Enable general debugging output.\n"
+ " --debug-format=opt1[,opt2,...]\n"
+ " Specify extra content in debugging output.\n"
+ " Options:\n"
+ " all\n"
+ " none\n"
+#ifdef HAVE_GETTIMEOFDAY
+ " timestamp\n"
+#endif
" --remote-debug Enable remote protocol debugging output.\n"
" --version Display version information and exit.\n"
" --wrapper WRAPPER -- Run WRAPPER to start new programs.\n"
kill_inferior_callback (struct inferior_list_entry *entry)
{
struct process_info *process = (struct process_info *) entry;
- int pid = ptid_get_pid (process->head.id);
+ int pid = ptid_get_pid (process->entry.id);
kill_inferior (pid);
discard_queued_stop_replies (pid);
detach_or_kill_inferior_callback (struct inferior_list_entry *entry)
{
struct process_info *process = (struct process_info *) entry;
- int pid = ptid_get_pid (process->head.id);
+ int pid = ptid_get_pid (process->entry.id);
if (process->attached)
detach_inferior (pid);
if (! process->attached)
{
- int pid = ptid_get_pid (process->head.id);
+ int pid = ptid_get_pid (process->entry.id);
fprintf (stderr, " %d", pid);
}
}
if (process->attached)
{
- int pid = ptid_get_pid (process->head.id);
+ int pid = ptid_get_pid (process->entry.id);
fprintf (stderr, " %d", pid);
}
}
}
else if (strcmp (*next_arg, "--debug") == 0)
debug_threads = 1;
+ else if (strncmp (*next_arg,
+ "--debug-format=",
+ sizeof ("--debug-format=") - 1) == 0)
+ {
+ char *error_msg
+ = parse_debug_format_options ((*next_arg)
+ + sizeof ("--debug-format=") - 1, 0);
+
+ if (error_msg != NULL)
+ {
+ fprintf (stderr, "%s", error_msg);
+ exit (1);
+ }
+ }
else if (strcmp (*next_arg, "--remote-debug") == 0)
remote_debug = 1;
else if (strcmp (*next_arg, "--disable-packet") == 0)
exit (1);
}
+ /* Remember stdio descriptors. LISTEN_DESC must not be listed, it will be
+ opened by remote_prepare. */
+ notice_open_fds ();
+
/* We need to know whether the remote connection is stdio before
starting the inferior. Inferiors created in this scenario have
stdin,stdout redirected. So do this here before we call
"Remote side has terminated connection. "
"GDBserver will reopen the connection.\n");
+ /* Get rid of any pending statuses. An eventual reconnection
+ (by the same GDB instance or another) will refresh all its
+ state from scratch. */
+ discard_queued_stop_replies (-1);
+ for_each_inferior (&all_threads, clear_pending_status_callback);
+
if (tracing)
{
if (disconnected_tracing)
}
}
+/* Skip PACKET until the next semi-colon (or end of string). */
+
+static void
+skip_to_semicolon (char **packet)
+{
+ while (**packet != '\0' && **packet != ';')
+ (*packet)++;
+}
+
/* Process options coming from Z packets for *point at address
POINT_ADDR. PACKET is the packet buffer. *PACKET is updated
to point to the first char after the last processed option. */
{
/* Conditional expression. */
if (debug_threads)
- fprintf (stderr, "Found breakpoint condition.\n");
- add_breakpoint_condition (point_addr, &dataptr);
+ debug_printf ("Found breakpoint condition.\n");
+ if (!add_breakpoint_condition (point_addr, &dataptr))
+ skip_to_semicolon (&dataptr);
}
else if (strncmp (dataptr, "cmds:", strlen ("cmds:")) == 0)
{
dataptr += strlen ("cmds:");
if (debug_threads)
- fprintf (stderr, "Found breakpoint commands %s.\n", dataptr);
+ debug_printf ("Found breakpoint commands %s.\n", dataptr);
persist = (*dataptr == '1');
dataptr += 2;
- add_breakpoint_commands (point_addr, &dataptr, persist);
+ if (add_breakpoint_commands (point_addr, &dataptr, persist))
+ skip_to_semicolon (&dataptr);
}
else
{
fprintf (stderr, "Unknown token %c, ignoring.\n",
*dataptr);
/* Skip tokens until we find one that we recognize. */
- while (*dataptr && *dataptr != ';')
- dataptr++;
+ skip_to_semicolon (&dataptr);
}
}
*packet = dataptr;
if (!non_stop)
{
if (debug_threads)
- fprintf (stderr, "Forcing non-stop mode\n");
+ debug_printf ("Forcing non-stop mode\n");
non_stop = 1;
start_non_stop (1);
break;
}
- thread_id = ((struct inferior_list_entry *)thread)->id;
+ thread_id = thread->entry.id;
}
else
{
(struct thread_info *) find_inferior_id (&all_threads,
general_thread);
if (thread == NULL)
- thread_id = all_threads.head->id;
+ {
+ thread = get_first_thread ();
+ thread_id = thread->entry.id;
+ }
}
general_thread = thread_id;
if (res < 0)
write_enn (own_buf);
else
- convert_int_to_ascii (mem_buf, own_buf, res);
+ bin2hex (mem_buf, own_buf, res);
break;
case 'M':
require_running (own_buf);
break;
case 'C':
require_running (own_buf);
- convert_ascii_to_int (own_buf + 1, &sig, 1);
+ hex2bin (own_buf + 1, &sig, 1);
if (gdb_signal_to_host_p (sig))
signal = gdb_signal_to_host (sig);
else
break;
case 'S':
require_running (own_buf);
- convert_ascii_to_int (own_buf + 1, &sig, 1);
+ hex2bin (own_buf + 1, &sig, 1);
if (gdb_signal_to_host_p (sig))
signal = gdb_signal_to_host (sig);
else
the whole vStopped list (until it gets an OK). */
if (QUEUE_is_empty (notif_event_p, notif_stop.queue))
{
- fprintf (stderr, "GDBserver exiting\n");
+ /* Be transparent when GDB is connected through stdio -- no
+ need to spam GDB's console. */
+ if (!remote_connection_is_stdio ())
+ fprintf (stderr, "GDBserver exiting\n");
remote_close ();
exit (0);
}
handle_serial_event (int err, gdb_client_data client_data)
{
if (debug_threads)
- fprintf (stderr, "handling possible serial event\n");
+ debug_printf ("handling possible serial event\n");
/* Really handle it. */
if (process_serial_event () < 0)
handle_target_event (int err, gdb_client_data client_data)
{
if (debug_threads)
- fprintf (stderr, "handling possible target event\n");
+ debug_printf ("handling possible target event\n");
last_ptid = mywait (minus_one_ptid, &last_status,
TARGET_WNOHANG, 1);
- if (last_status.kind != TARGET_WAITKIND_IGNORE)
+ if (last_status.kind == TARGET_WAITKIND_NO_RESUMED)
+ {
+ /* No RSP support for this yet. */
+ }
+ else if (last_status.kind != TARGET_WAITKIND_IGNORE)
{
int pid = ptid_get_pid (last_ptid);
struct process_info *process = find_process_pid (pid);
struct thread_resume resume_info;
if (debug_threads)
- fprintf (stderr,
- "GDB not connected; forwarding event %d for [%s]\n",
- (int) last_status.kind,
- target_pid_to_str (last_ptid));
+ debug_printf ("GDB not connected; forwarding event %d for"
+ " [%s]\n",
+ (int) last_status.kind,
+ target_pid_to_str (last_ptid));
resume_info.thread = last_ptid;
resume_info.kind = resume_continue;
(*the_target->resume) (&resume_info, 1);
}
else if (debug_threads)
- fprintf (stderr, "GDB not connected; ignoring event %d for [%s]\n",
- (int) last_status.kind,
- target_pid_to_str (last_ptid));
+ debug_printf ("GDB not connected; ignoring event %d for [%s]\n",
+ (int) last_status.kind,
+ target_pid_to_str (last_ptid));
}
else
{