gdbserver:server.c - use unpack_varlen_hex to extract hex numbers.
[deliverable/binutils-gdb.git] / gdb / gdbserver / server.c
index 61a731304152c54e6597053b4e50ba1c58f7d56b..371647c06660c9cbd4bf6a3d7b4be3925b7a82e5 100644 (file)
@@ -1,6 +1,5 @@
 /* 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.
 
@@ -20,6 +19,7 @@
 #include "server.h"
 #include "gdbthread.h"
 #include "agent.h"
+#include "notif.h"
 
 #if HAVE_UNISTD_H
 #include <unistd.h>
@@ -27,9 +27,7 @@
 #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
@@ -117,13 +115,13 @@ static ptid_t last_ptid;
 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;
@@ -132,66 +130,39 @@ struct vstop_notif
   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 (&notif_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, &notif_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
@@ -200,40 +171,23 @@ push_event (ptid_t ptid, struct target_waitstatus *status)
 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,
-                         &notif_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)
 {
@@ -1854,12 +1808,12 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
     {
       /* 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);
@@ -2171,29 +2125,6 @@ handle_v_kill (char *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)
@@ -2254,11 +2185,8 @@ 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.  */
@@ -2283,8 +2211,7 @@ myresume (char *own_buf, int step, int sig)
 
   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
@@ -2340,9 +2267,14 @@ queue_stop_reply_callback (struct inferior_list_entry *entry, void *arg)
      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 (&notif_stop,
+                        (struct notif_event *) new_notif);
     }
   else
     {
@@ -2423,7 +2355,7 @@ handle_status (char *own_buf)
       /* 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 (&notif_stop, own_buf);
     }
   else
     {
@@ -2449,7 +2381,7 @@ static void
 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",
@@ -2755,6 +2687,7 @@ main (int argc, char *argv[])
 
   initialize_async_io ();
   initialize_low ();
+  initialize_event_loop ();
   if (target_supports_tracepoints ())
     initialize_tracepoint ();
 
@@ -2792,6 +2725,8 @@ main (int argc, char *argv[])
       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.  */
@@ -3006,8 +2941,7 @@ process_serial_event (void)
          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 ())
        {
@@ -3258,13 +3192,16 @@ process_serial_event (void)
       /* 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;
@@ -3404,7 +3341,7 @@ process_serial_event (void)
     {
       /* 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 ();
@@ -3502,8 +3439,14 @@ handle_target_event (int err, gdb_client_data client_data)
        }
       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 (&notif_stop,
+                     (struct notif_event *) vstop_notif);
        }
     }
 
This page took 0.029223 seconds and 4 git commands to generate.