/* Main code for remote server for GDB.
- Copyright (C) 1989, 1993-1995, 1997-2000, 2002-2012 Free Software
- Foundation, Inc.
+ Copyright (C) 1989-2013 Free Software Foundation, Inc.
This file is part of GDB.
#include "server.h"
#include "gdbthread.h"
#include "agent.h"
+#include "notif.h"
#if HAVE_UNISTD_H
#include <unistd.h>
#if HAVE_SIGNAL_H
#include <signal.h>
#endif
-#if HAVE_SYS_WAIT_H
-#include <sys/wait.h>
-#endif
+#include "gdb_wait.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 *own_buf;
static unsigned char *mem_buf;
-/* Structure holding information relative to a single stop reply. We
- keep a queue of these (really a singly-linked list) to push to GDB
- in non-stop mode. */
+/* A sub-class of 'struct notif_event' for stop, holding information
+ relative to a single stop reply. We keep a queue of these to
+ push to GDB in non-stop mode. */
+
struct vstop_notif
{
- /* Pointer to next in list. */
- struct vstop_notif *next;
+ struct notif_event base;
/* Thread or process that got the event. */
ptid_t ptid;
struct target_waitstatus status;
};
-/* The pending stop replies list head. */
-static struct vstop_notif *notif_queue = NULL;
+DEFINE_QUEUE_P (notif_event_p);
/* Put a stop reply to the stop reply queue. */
static void
queue_stop_reply (ptid_t ptid, struct target_waitstatus *status)
{
- struct vstop_notif *new_notif;
+ struct vstop_notif *new_notif = xmalloc (sizeof (*new_notif));
- new_notif = xmalloc (sizeof (*new_notif));
- new_notif->next = NULL;
new_notif->ptid = ptid;
new_notif->status = *status;
- if (notif_queue)
- {
- struct vstop_notif *tail;
- for (tail = notif_queue;
- tail && tail->next;
- tail = tail->next)
- ;
- tail->next = new_notif;
- }
- else
- notif_queue = new_notif;
-
- if (remote_debug)
- {
- int i = 0;
- struct vstop_notif *n;
-
- for (n = notif_queue; n; n = n->next)
- i++;
-
- fprintf (stderr, "pending stop replies: %d\n", i);
- }
+ notif_event_enque (¬if_stop, (struct notif_event *) new_notif);
}
-/* Place an event in the stop reply queue, and push a notification if
- we aren't sending one yet. */
-
-void
-push_event (ptid_t ptid, struct target_waitstatus *status)
+static int
+remove_all_on_match_pid (QUEUE (notif_event_p) *q,
+ QUEUE_ITER (notif_event_p) *iter,
+ struct notif_event *event,
+ void *data)
{
- gdb_assert (status->kind != TARGET_WAITKIND_IGNORE);
+ int *pid = data;
- queue_stop_reply (ptid, status);
-
- /* If this is the first stop reply in the queue, then inform GDB
- about it, by sending a Stop notification. */
- if (notif_queue->next == NULL)
+ if (*pid == -1
+ || ptid_get_pid (((struct vstop_notif *) event)->ptid) == *pid)
{
- char *p = own_buf;
- strcpy (p, "Stop:");
- p += strlen (p);
- prepare_resume_reply (p,
- notif_queue->ptid, ¬if_queue->status);
- putpkt_notif (own_buf);
+ if (q->free_func != NULL)
+ q->free_func (event);
+
+ QUEUE_remove_elem (notif_event_p, q, iter);
}
+
+ return 1;
}
/* Get rid of the currently pending stop replies for PID. If PID is
static void
discard_queued_stop_replies (int pid)
{
- struct vstop_notif *prev = NULL, *reply, *next;
-
- for (reply = notif_queue; reply; reply = next)
- {
- next = reply->next;
-
- if (pid == -1
- || ptid_get_pid (reply->ptid) == pid)
- {
- if (reply == notif_queue)
- notif_queue = next;
- else
- prev->next = reply->next;
-
- free (reply);
- }
- else
- prev = reply;
- }
+ QUEUE_iterate (notif_event_p, notif_stop.queue,
+ remove_all_on_match_pid, &pid);
}
-/* If there are more stop replies to push, push one now. */
-
static void
-send_next_stop_reply (char *own_buf)
+vstop_notif_reply (struct notif_event *event, char *own_buf)
{
- if (notif_queue)
- prepare_resume_reply (own_buf,
- notif_queue->ptid,
- ¬if_queue->status);
- else
- write_ok (own_buf);
+ struct vstop_notif *vstop = (struct vstop_notif *) event;
+
+ prepare_resume_reply (own_buf, vstop->ptid, &vstop->status);
}
+struct notif_server notif_stop =
+{
+ "vStopped", "Stop", NULL, vstop_notif_reply,
+};
+
static int
target_running (void)
{
{
/* CRC check (compare-section). */
char *comma;
- CORE_ADDR base;
+ ULONGEST base;
int len;
unsigned long long crc;
require_running (own_buf);
- base = strtoul (own_buf + 5, &comma, 16);
+ comma = unpack_varlen_hex (own_buf + 5, &base);
if (*comma++ != ',')
{
write_enn (own_buf);
}
}
-/* Handle a 'vStopped' packet. */
-static void
-handle_v_stopped (char *own_buf)
-{
- /* If we're waiting for GDB to acknowledge a pending stop reply,
- consider that done. */
- if (notif_queue)
- {
- struct vstop_notif *head;
-
- if (remote_debug)
- fprintf (stderr, "vStopped: acking %s\n",
- target_pid_to_str (notif_queue->ptid));
-
- head = notif_queue;
- notif_queue = notif_queue->next;
- free (head);
- }
-
- /* Push another stop reply, or if there are no more left, an OK. */
- send_next_stop_reply (own_buf);
-}
-
/* Handle all of the extended 'v' packets. */
void
handle_v_requests (char *own_buf, int packet_len, int *new_packet_len)
return;
}
- if (strncmp (own_buf, "vStopped", 8) == 0)
- {
- handle_v_stopped (own_buf);
- return;
- }
+ if (handle_notif_ack (own_buf, packet_len))
+ return;
/* Otherwise we didn't know what packet it was. Say we didn't
understand it. */
if (step || sig || valid_cont_thread)
{
- resume_info[0].thread
- = ((struct inferior_list_entry *) current_inferior)->id;
+ resume_info[0].thread = current_ptid;
if (step)
resume_info[0].kind = resume_step;
else
manage the thread's last_status field. */
if (the_target->thread_stopped == NULL)
{
+ struct vstop_notif *new_notif = xmalloc (sizeof (*new_notif));
+
+ new_notif->ptid = entry->id;
+ new_notif->status = thread->last_status;
/* Pass the last stop reply back to GDB, but don't notify
yet. */
- queue_stop_reply (entry->id, &thread->last_status);
+ notif_event_enque (¬if_stop,
+ (struct notif_event *) new_notif);
}
else
{
/* The first is sent immediatly. OK is sent if there is no
stopped thread, which is the same handling of the vStopped
packet (by design). */
- send_next_stop_reply (own_buf);
+ notif_write_event (¬if_stop, own_buf);
}
else
{
gdbserver_version (void)
{
printf ("GNU gdbserver %s%s\n"
- "Copyright (C) 2012 Free Software Foundation, Inc.\n"
+ "Copyright (C) 2013 Free Software Foundation, Inc.\n"
"gdbserver is free software, covered by the "
"GNU General Public License.\n"
"This gdbserver was configured as \"%s\"\n",
initialize_async_io ();
initialize_low ();
+ initialize_event_loop ();
if (target_supports_tracepoints ())
initialize_tracepoint ();
last_ptid = minus_one_ptid;
}
+ initialize_notif ();
+
/* Don't report shared library events on the initial connection,
even if some libraries are preloaded. Avoids the "stopped by
shared library event" notice on gdb side. */
pid = strtol (&own_buf[i], NULL, 16);
}
else
- pid =
- ptid_get_pid (((struct inferior_list_entry *) current_inferior)->id);
+ pid = ptid_get_pid (current_ptid);
if ((tracing && disconnected_tracing) || any_persistent_commands ())
{
/* Fallthrough. */
case 'z': /* remove_ ... */
{
- char *lenptr;
char *dataptr;
- CORE_ADDR addr = strtoul (&own_buf[3], &lenptr, 16);
- int len = strtol (lenptr + 1, &dataptr, 16);
+ ULONGEST addr;
+ int len;
char type = own_buf[1];
int res;
const int insert = ch == 'Z';
+ char *p = &own_buf[3];
+
+ p = unpack_varlen_hex (p, &addr);
+ len = strtol (p + 1, &dataptr, 16);
/* Default to unrecognized/unsupported. */
res = 1;
{
/* In non-stop, defer exiting until GDB had a chance to query
the whole vStopped list (until it gets an OK). */
- if (!notif_queue)
+ if (QUEUE_is_empty (notif_event_p, notif_stop.queue))
{
fprintf (stderr, "GDBserver exiting\n");
remote_close ();
}
else
{
- /* Something interesting. Tell GDB about it. */
- push_event (last_ptid, &last_status);
+ struct vstop_notif *vstop_notif
+ = xmalloc (sizeof (struct vstop_notif));
+
+ vstop_notif->status = last_status;
+ vstop_notif->ptid = last_ptid;
+ /* Push Stop notification. */
+ notif_push (¬if_stop,
+ (struct notif_event *) vstop_notif);
}
}