gdb/gdbserver:
[deliverable/binutils-gdb.git] / gdb / gdbserver / server.c
index 76c2e0ec5505f7b98d8311deb557d4175fb8c13e..b3d1b41186b3fa7c41c52888d5cc87dddb2697e8 100644 (file)
@@ -1,6 +1,6 @@
 /* Main code for remote server for GDB.
-   Copyright (C) 1989, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2002, 2003,
-   2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+   Copyright (C) 1989, 1993-1995, 1997-2000, 2002-2012 Free Software
+   Foundation, Inc.
 
    This file is part of GDB.
 
@@ -18,6 +18,8 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "server.h"
+#include "gdbthread.h"
+#include "agent.h"
 
 #if HAVE_UNISTD_H
 #include <unistd.h>
 #if HAVE_SYS_WAIT_H
 #include <sys/wait.h>
 #endif
-#if HAVE_MALLOC_H
-#include <malloc.h>
-#endif
 
+/* The thread set with an `Hc' packet.  `Hc' is deprecated in favor of
+   `vCont'.  Note the multi-process extensions made `vCont' a
+   requirement, so `Hc pPID.TID' is pretty much undefined.  So
+   CONT_THREAD can be null_ptid for no `Hc' thread, minus_one_ptid for
+   resuming all threads of the process (again, `Hc' isn't used for
+   multi-process), or a specific thread ptid_t.
+
+   We also set this when handling a single-thread `vCont' resume, as
+   some places in the backends check it to know when (and for which
+   thread) single-thread scheduler-locking is in effect.  */
 ptid_t cont_thread;
+
+/* The thread set with an `Hg' packet.  */
 ptid_t general_thread;
-ptid_t step_thread;
 
 int server_waiting;
 
@@ -42,16 +52,28 @@ static int extended_protocol;
 static int response_needed;
 static int exit_requested;
 
+/* --once: Exit after the first connection has closed.  */
+int run_once;
+
 int multi_process;
 int non_stop;
 
+/* Whether we should attempt to disable the operating system's address
+   space randomization feature before starting an inferior.  */
+int disable_randomization = 1;
+
 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;
+
 int pass_signals[TARGET_SIGNAL_LAST];
+int program_signals[TARGET_SIGNAL_LAST];
+int program_signals_p;
 
 jmp_buf toplevel;
 
@@ -120,7 +142,7 @@ queue_stop_reply (ptid_t ptid, struct target_waitstatus *status)
 {
   struct vstop_notif *new_notif;
 
-  new_notif = malloc (sizeof (*new_notif));
+  new_notif = xmalloc (sizeof (*new_notif));
   new_notif->next = NULL;
   new_notif->ptid = ptid;
   new_notif->status = *status;
@@ -155,6 +177,8 @@ queue_stop_reply (ptid_t ptid, struct target_waitstatus *status)
 void
 push_event (ptid_t ptid, struct target_waitstatus *status)
 {
+  gdb_assert (status->kind != TARGET_WAITKIND_IGNORE);
+
   queue_stop_reply (ptid, status);
 
   /* If this is the first stop reply in the queue, then inform GDB
@@ -238,11 +262,23 @@ start_inferior (char **argv)
       new_argv[count] = NULL;
     }
 
+  if (debug_threads)
+    {
+      int i;
+      for (i = 0; new_argv[i]; ++i)
+       fprintf (stderr, "new_argv[%d] = \"%s\"\n", i, new_argv[i]);
+      fflush (stderr);
+    }
+
 #ifdef SIGTTOU
   signal (SIGTTOU, SIG_DFL);
   signal (SIGTTIN, SIG_DFL);
 #endif
 
+  /* Clear this so the backend doesn't get confused, thinking
+     CONT_THREAD died, and it needs to resume all threads.  */
+  cont_thread = null_ptid;
+
   signal_pid = create_inferior (new_argv[0], new_argv);
 
   /* FIXME: we don't actually know at this point that the create
@@ -263,13 +299,12 @@ start_inferior (char **argv)
   if (wrapper_argv != NULL)
     {
       struct thread_resume resume_info;
-      ptid_t ptid;
 
       resume_info.thread = pid_to_ptid (signal_pid);
       resume_info.kind = resume_continue;
       resume_info.sig = 0;
 
-      ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
+      last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
 
       if (last_status.kind != TARGET_WAITKIND_STOPPED)
        return signal_pid;
@@ -278,12 +313,17 @@ start_inferior (char **argv)
        {
          (*the_target->resume) (&resume_info, 1);
 
-         mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
+         last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
          if (last_status.kind != TARGET_WAITKIND_STOPPED)
            return signal_pid;
+
+         current_inferior->last_resume_kind = resume_stop;
+         current_inferior->last_status = last_status;
        }
       while (last_status.value.sig != TARGET_SIGNAL_TRAP);
 
+      current_inferior->last_resume_kind = resume_stop;
+      current_inferior->last_status = last_status;
       return signal_pid;
     }
 
@@ -291,6 +331,13 @@ start_inferior (char **argv)
      (assuming success).  */
   last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
 
+  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;
+    }
+
   return signal_pid;
 }
 
@@ -311,6 +358,10 @@ attach_inferior (int pid)
      whichever we were told to attach to.  */
   signal_pid = pid;
 
+  /* Clear this so the backend doesn't get confused, thinking
+     CONT_THREAD died, and it needs to resume all threads.  */
+  cont_thread = null_ptid;
+
   if (!non_stop)
     {
       last_ptid = mywait (pid_to_ptid (pid), &last_status, 0, 0);
@@ -321,6 +372,9 @@ attach_inferior (int pid)
       if (last_status.kind == TARGET_WAITKIND_STOPPED
          && last_status.value.sig == TARGET_SIGNAL_STOP)
        last_status.value.sig = TARGET_SIGNAL_TRAP;
+
+      current_inferior->last_resume_kind = resume_stop;
+      current_inferior->last_status = last_status;
     }
 
   return 0;
@@ -332,8 +386,34 @@ extern int remote_debug;
    or -1 otherwise.  */
 
 static int
-decode_xfer_read (char *buf, char **annex, CORE_ADDR *ofs, unsigned int *len)
+decode_xfer_read (char *buf, CORE_ADDR *ofs, unsigned int *len)
+{
+  /* After the read marker and annex, qXfer looks like a
+     traditional 'm' packet.  */
+  decode_m_packet (buf, ofs, len);
+
+  return 0;
+}
+
+static int
+decode_xfer (char *buf, char **object, char **rw, char **annex, char **offset)
 {
+  /* Extract and NUL-terminate the object.  */
+  *object = buf;
+  while (*buf && *buf != ':')
+    buf++;
+  if (*buf == '\0')
+    return -1;
+  *buf++ = 0;
+
+  /* Extract and NUL-terminate the read/write action.  */
+  *rw = buf;
+  while (*buf && *buf != ':')
+    buf++;
+  if (*buf == '\0')
+    return -1;
+  *buf++ = 0;
+
   /* Extract and NUL-terminate the annex.  */
   *annex = buf;
   while (*buf && *buf != ':')
@@ -342,10 +422,7 @@ decode_xfer_read (char *buf, char **annex, CORE_ADDR *ofs, unsigned int *len)
     return -1;
   *buf++ = 0;
 
-  /* After the read marker and annex, qXfer looks like a
-     traditional 'm' packet.  */
-  decode_m_packet (buf, ofs, len);
-
+  *offset = buf;
   return 0;
 }
 
@@ -368,7 +445,8 @@ write_qxfer_response (char *buf, const void *data, int len, int is_more)
 }
 
 /* Handle all of the extended 'Q' packets.  */
-void
+
+static void
 handle_general_set (char *own_buf)
 {
   if (strncmp ("QPassSignals:", own_buf, strlen ("QPassSignals:")) == 0)
@@ -396,6 +474,33 @@ handle_general_set (char *own_buf)
       return;
     }
 
+  if (strncmp ("QProgramSignals:", own_buf, strlen ("QProgramSignals:")) == 0)
+    {
+      int numsigs = (int) TARGET_SIGNAL_LAST, i;
+      const char *p = own_buf + strlen ("QProgramSignals:");
+      CORE_ADDR cursig;
+
+      program_signals_p = 1;
+
+      p = decode_address_to_semicolon (&cursig, p);
+      for (i = 0; i < numsigs; i++)
+       {
+         if (i == cursig)
+           {
+             program_signals[i] = 1;
+             if (*p == '\0')
+               /* Keep looping, to clear the remaining signals.  */
+               cursig = -1;
+             else
+               p = decode_address_to_semicolon (&cursig, p);
+           }
+         else
+           program_signals[i] = 0;
+       }
+      strcpy (own_buf, "OK");
+      return;
+    }
+
   if (strcmp (own_buf, "QStartNoAckMode") == 0)
     {
       if (remote_debug)
@@ -446,6 +551,55 @@ handle_general_set (char *own_buf)
       return;
     }
 
+  if (strncmp ("QDisableRandomization:", own_buf,
+              strlen ("QDisableRandomization:")) == 0)
+    {
+      char *packet = own_buf + strlen ("QDisableRandomization:");
+      ULONGEST setting;
+
+      unpack_varlen_hex (packet, &setting);
+      disable_randomization = setting;
+
+      if (remote_debug)
+       {
+         if (disable_randomization)
+           fprintf (stderr, "[address space randomization disabled]\n");
+         else
+           fprintf (stderr, "[address space randomization enabled]\n");
+       }
+
+      write_ok (own_buf);
+      return;
+    }
+
+  if (target_supports_tracepoints ()
+      && handle_tracepoint_general_set (own_buf))
+    return;
+
+  if (strncmp ("QAgent:", own_buf, strlen ("QAgent:")) == 0)
+    {
+      char *mode = own_buf + strlen ("QAgent:");
+      int req = 0;
+
+      if (strcmp (mode, "0") == 0)
+       req = 0;
+      else if (strcmp (mode, "1") == 0)
+       req = 1;
+      else
+       {
+         /* We don't know what this value is, so complain to GDB.  */
+         sprintf (own_buf, "E.Unknown QAgent value");
+         return;
+       }
+
+      /* Update the flag.  */
+      use_agent = req;
+      if (remote_debug)
+       fprintf (stderr, "[%s agent]\n", req ? "Enable" : "Disable");
+      write_ok (own_buf);
+      return;
+    }
+
   /* Otherwise we didn't know what packet it was.  Say we didn't
      understand it.  */
   own_buf[0] = 0;
@@ -495,12 +649,80 @@ monitor_show_help (void)
   monitor_output ("The following monitor commands are supported:\n");
   monitor_output ("  set debug <0|1>\n");
   monitor_output ("    Enable general debugging messages\n");
+  monitor_output ("  set debug-hw-points <0|1>\n");
+  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 ("  exit\n");
   monitor_output ("    Quit GDBserver\n");
 }
 
+/* Read trace frame or inferior memory.  Returns the number of bytes
+   actually read, zero when no further transfer is possible, and -1 on
+   error.  Return of a positive value smaller than LEN does not
+   indicate there's no more to be read, only the end of the transfer.
+   E.g., when GDB reads memory from a traceframe, a first request may
+   be served from a memory block that does not cover the whole request
+   length.  A following request gets the rest served from either
+   another block (of the same traceframe) or from the read-only
+   regions.  */
+
+static int
+gdb_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
+{
+  int res;
+
+  if (current_traceframe >= 0)
+    {
+      ULONGEST nbytes;
+      ULONGEST length = len;
+
+      if (traceframe_read_mem (current_traceframe,
+                              memaddr, myaddr, len, &nbytes))
+       return EIO;
+      /* Data read from trace buffer, we're done.  */
+      if (nbytes > 0)
+       return nbytes;
+      if (!in_readonly_region (memaddr, length))
+       return -1;
+      /* Otherwise we have a valid readonly case, fall through.  */
+      /* (assume no half-trace half-real blocks for now) */
+    }
+
+  res = prepare_to_access_memory ();
+  if (res == 0)
+    {
+      res = read_inferior_memory (memaddr, myaddr, len);
+      done_accessing_memory ();
+
+      return res == 0 ? len : -1;
+    }
+  else
+    return -1;
+}
+
+/* Write trace frame or inferior memory.  Actually, writing to trace
+   frames is forbidden.  */
+
+static int
+gdb_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
+{
+  if (current_traceframe >= 0)
+    return EIO;
+  else
+    {
+      int ret;
+
+      ret = prepare_to_access_memory ();
+      if (ret == 0)
+       {
+         ret = write_inferior_memory (memaddr, myaddr, len);
+         done_accessing_memory ();
+       }
+      return ret;
+    }
+}
+
 /* Subroutine of handle_search_memory to simplify it.  */
 
 static int
@@ -512,7 +734,8 @@ handle_search_memory_1 (CORE_ADDR start_addr, CORE_ADDR search_space_len,
 {
   /* Prime the search buffer.  */
 
-  if (read_inferior_memory (start_addr, search_buf, search_buf_size) != 0)
+  if (gdb_read_memory (start_addr, search_buf, search_buf_size)
+      != search_buf_size)
     {
       warning ("Unable to access target memory at 0x%lx, halting search.",
               (long) start_addr);
@@ -552,7 +775,7 @@ handle_search_memory_1 (CORE_ADDR start_addr, CORE_ADDR search_space_len,
       if (search_space_len >= pattern_len)
        {
          unsigned keep_len = search_buf_size - chunk_size;
-         CORE_ADDR read_addr = start_addr + keep_len;
+         CORE_ADDR read_addr = start_addr + chunk_size + keep_len;
          int nr_to_read;
 
          /* Copy the trailing part of the previous iteration to the front
@@ -563,10 +786,11 @@ handle_search_memory_1 (CORE_ADDR start_addr, CORE_ADDR search_space_len,
                        ? search_space_len - keep_len
                        : chunk_size);
 
-         if (read_inferior_memory (read_addr, search_buf + keep_len,
-                                   nr_to_read) != 0)
+         if (gdb_read_memory (read_addr, search_buf + keep_len,
+                              nr_to_read) != search_buf_size)
            {
-             warning ("Unable to access target memory at 0x%lx, halting search.",
+             warning ("Unable to access target memory "
+                      "at 0x%lx, halting search.",
                       (long) read_addr);
              return -1;
            }
@@ -655,408 +879,693 @@ handle_search_memory (char *own_buf, int packet_len)
       return;                                  \
     }
 
-/* Handle all of the extended 'q' packets.  */
-void
-handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
-{
-  static struct inferior_list_entry *thread_ptr;
+/* Handle monitor commands not handled by target-specific handlers.  */
 
-  /* Reply the current thread id.  */
-  if (strcmp ("qC", own_buf) == 0 && !disable_packet_qC)
+static void
+handle_monitor_command (char *mon, char *own_buf)
+{
+  if (strcmp (mon, "set debug 1") == 0)
     {
-      ptid_t gdb_id;
-      require_running (own_buf);
+      debug_threads = 1;
+      monitor_output ("Debug output enabled.\n");
+    }
+  else if (strcmp (mon, "set debug 0") == 0)
+    {
+      debug_threads = 0;
+      monitor_output ("Debug output disabled.\n");
+    }
+  else if (strcmp (mon, "set debug-hw-points 1") == 0)
+    {
+      debug_hw_points = 1;
+      monitor_output ("H/W point debugging output enabled.\n");
+    }
+  else if (strcmp (mon, "set debug-hw-points 0") == 0)
+    {
+      debug_hw_points = 0;
+      monitor_output ("H/W point debugging output disabled.\n");
+    }
+  else if (strcmp (mon, "set remote-debug 1") == 0)
+    {
+      remote_debug = 1;
+      monitor_output ("Protocol debug output enabled.\n");
+    }
+  else if (strcmp (mon, "set remote-debug 0") == 0)
+    {
+      remote_debug = 0;
+      monitor_output ("Protocol debug output disabled.\n");
+    }
+  else if (strcmp (mon, "help") == 0)
+    monitor_show_help ();
+  else if (strcmp (mon, "exit") == 0)
+    exit_requested = 1;
+  else
+    {
+      monitor_output ("Unknown monitor command.\n\n");
+      monitor_show_help ();
+      write_enn (own_buf);
+    }
+}
 
-      if (!ptid_equal (general_thread, null_ptid)
-         && !ptid_equal (general_thread, minus_one_ptid))
-       gdb_id = general_thread;
-      else
-       {
-         thread_ptr = all_threads.head;
-         gdb_id = thread_to_gdb_id ((struct thread_info *)thread_ptr);
-       }
+/* Associates a callback with each supported qXfer'able object.  */
 
-      sprintf (own_buf, "QC");
-      own_buf += 2;
-      own_buf = write_ptid (own_buf, gdb_id);
-      return;
-    }
+struct qxfer
+{
+  /* The object this handler handles.  */
+  const char *object;
+
+  /* Request that the target transfer up to LEN 8-bit bytes of the
+     target's OBJECT.  The OFFSET, for a seekable object, specifies
+     the starting point.  The ANNEX can be used to provide additional
+     data-specific information to the target.
+
+     Return the number of bytes actually transfered, zero when no
+     further transfer is possible, -1 on error, and -2 when the
+     transfer is not supported.  Return of a positive value smaller
+     than LEN does not indicate the end of the object, only the end of
+     the transfer.
+
+     One, and only one, of readbuf or writebuf must be non-NULL.  */
+  int (*xfer) (const char *annex,
+              gdb_byte *readbuf, const gdb_byte *writebuf,
+              ULONGEST offset, LONGEST len);
+};
 
-  if (strcmp ("qSymbol::", own_buf) == 0)
+/* Handle qXfer:auxv:read.  */
+
+static int
+handle_qxfer_auxv (const char *annex,
+                  gdb_byte *readbuf, const gdb_byte *writebuf,
+                  ULONGEST offset, LONGEST len)
+{
+  if (the_target->read_auxv == NULL || writebuf != NULL)
+    return -2;
+
+  if (annex[0] != '\0' || !target_running ())
+    return -1;
+
+  return (*the_target->read_auxv) (offset, readbuf, len);
+}
+
+/* Handle qXfer:features:read.  */
+
+static int
+handle_qxfer_features (const char *annex,
+                      gdb_byte *readbuf, const gdb_byte *writebuf,
+                      ULONGEST offset, LONGEST len)
+{
+  const char *document;
+  size_t total_len;
+
+  if (writebuf != NULL)
+    return -2;
+
+  if (!target_running ())
+    return -1;
+
+  /* Grab the correct annex.  */
+  document = get_features_xml (annex);
+  if (document == NULL)
+    return -1;
+
+  total_len = strlen (document);
+
+  if (offset > total_len)
+    return -1;
+
+  if (offset + len > total_len)
+    len = total_len - offset;
+
+  memcpy (readbuf, document + offset, len);
+  return len;
+}
+
+/* Handle qXfer:libraries:read.  */
+
+static int
+handle_qxfer_libraries (const char *annex,
+                       gdb_byte *readbuf, const gdb_byte *writebuf,
+                       ULONGEST offset, LONGEST len)
+{
+  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);
+
+  document = malloc (total_len);
+  if (document == NULL)
+    return -1;
+
+  strcpy (document, "<library-list>\n");
+  p = document + strlen (document);
+
+  for (dll_ptr = all_dlls.head; dll_ptr != NULL; dll_ptr = dll_ptr->next)
     {
-      if (target_running () && the_target->look_up_symbols != NULL)
-       (*the_target->look_up_symbols) ();
+      struct dll_info *dll = (struct dll_info *) dll_ptr;
+      char *name;
 
-      strcpy (own_buf, "OK");
-      return;
+      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);
     }
 
-  if (!disable_packet_qfThreadInfo)
+  strcpy (p, "</library-list>\n");
+
+  total_len = strlen (document);
+
+  if (offset > total_len)
     {
-      if (strcmp ("qfThreadInfo", own_buf) == 0)
-       {
-         ptid_t gdb_id;
+      free (document);
+      return -1;
+    }
 
-         require_running (own_buf);
-         thread_ptr = all_threads.head;
+  if (offset + len > total_len)
+    len = total_len - offset;
 
-         *own_buf++ = 'm';
-         gdb_id = thread_to_gdb_id ((struct thread_info *)thread_ptr);
-         write_ptid (own_buf, gdb_id);
-         thread_ptr = thread_ptr->next;
-         return;
-       }
+  memcpy (readbuf, document + offset, len);
+  free (document);
+  return len;
+}
 
-      if (strcmp ("qsThreadInfo", own_buf) == 0)
-       {
-         ptid_t gdb_id;
+/* Handle qXfer:libraries-svr4:read.  */
 
-         require_running (own_buf);
-         if (thread_ptr != NULL)
-           {
-             *own_buf++ = 'm';
-             gdb_id = thread_to_gdb_id ((struct thread_info *)thread_ptr);
-             write_ptid (own_buf, gdb_id);
-             thread_ptr = thread_ptr->next;
-             return;
-           }
-         else
-           {
-             sprintf (own_buf, "l");
-             return;
-           }
-       }
-    }
+static int
+handle_qxfer_libraries_svr4 (const char *annex,
+                            gdb_byte *readbuf, const gdb_byte *writebuf,
+                            ULONGEST offset, LONGEST len)
+{
+  if (writebuf != NULL)
+    return -2;
 
-  if (the_target->read_offsets != NULL
-      && strcmp ("qOffsets", own_buf) == 0)
-    {
-      CORE_ADDR text, data;
+  if (annex[0] != '\0' || !target_running ()
+      || the_target->qxfer_libraries_svr4 == NULL)
+    return -1;
 
-      require_running (own_buf);
-      if (the_target->read_offsets (&text, &data))
-       sprintf (own_buf, "Text=%lX;Data=%lX;Bss=%lX",
-                (long)text, (long)data, (long)data);
-      else
-       write_enn (own_buf);
+  return the_target->qxfer_libraries_svr4 (annex, readbuf, writebuf, offset, len);
+}
 
-      return;
-    }
+/* Handle qXfer:osadata:read.  */
 
-  if (the_target->qxfer_spu != NULL
-      && strncmp ("qXfer:spu:read:", own_buf, 15) == 0)
-    {
-      char *annex;
-      int n;
-      unsigned int len;
-      CORE_ADDR ofs;
-      unsigned char *spu_buf;
+static int
+handle_qxfer_osdata (const char *annex,
+                    gdb_byte *readbuf, const gdb_byte *writebuf,
+                    ULONGEST offset, LONGEST len)
+{
+  if (the_target->qxfer_osdata == NULL || writebuf != NULL)
+    return -2;
 
-      require_running (own_buf);
-      strcpy (own_buf, "E00");
-      if (decode_xfer_read (own_buf + 15, &annex, &ofs, &len) < 0)
-       return;
-      if (len > PBUFSIZ - 2)
-       len = PBUFSIZ - 2;
-      spu_buf = malloc (len + 1);
-      if (!spu_buf)
-       return;
-
-      n = (*the_target->qxfer_spu) (annex, spu_buf, NULL, ofs, len + 1);
-      if (n < 0)
-       write_enn (own_buf);
-      else if (n > len)
-       *new_packet_len_p = write_qxfer_response (own_buf, spu_buf, len, 1);
-      else
-       *new_packet_len_p = write_qxfer_response (own_buf, spu_buf, n, 0);
+  return (*the_target->qxfer_osdata) (annex, readbuf, NULL, offset, len);
+}
 
-      free (spu_buf);
-      return;
-    }
+/* Handle qXfer:siginfo:read and qXfer:siginfo:write.  */
 
-  if (the_target->qxfer_spu != NULL
-      && strncmp ("qXfer:spu:write:", own_buf, 16) == 0)
-    {
-      char *annex;
-      int n;
-      unsigned int len;
-      CORE_ADDR ofs;
-      unsigned char *spu_buf;
+static int
+handle_qxfer_siginfo (const char *annex,
+                     gdb_byte *readbuf, const gdb_byte *writebuf,
+                     ULONGEST offset, LONGEST len)
+{
+  if (the_target->qxfer_siginfo == NULL)
+    return -2;
 
-      require_running (own_buf);
-      strcpy (own_buf, "E00");
-      spu_buf = malloc (packet_len - 15);
-      if (!spu_buf)
-       return;
-      if (decode_xfer_write (own_buf + 16, packet_len - 16, &annex,
-                            &ofs, &len, spu_buf) < 0)
-       {
-         free (spu_buf);
-         return;
-       }
+  if (annex[0] != '\0' || !target_running ())
+    return -1;
 
-      n = (*the_target->qxfer_spu)
-       (annex, NULL, (unsigned const char *)spu_buf, ofs, len);
-      if (n < 0)
-       write_enn (own_buf);
-      else
-       sprintf (own_buf, "%x", n);
+  return (*the_target->qxfer_siginfo) (annex, readbuf, writebuf, offset, len);
+}
 
-      free (spu_buf);
-      return;
-    }
+/* Handle qXfer:spu:read and qXfer:spu:write.  */
 
-  if (the_target->read_auxv != NULL
-      && strncmp ("qXfer:auxv:read:", own_buf, 16) == 0)
+static int
+handle_qxfer_spu (const char *annex,
+                 gdb_byte *readbuf, const gdb_byte *writebuf,
+                 ULONGEST offset, LONGEST len)
+{
+  if (the_target->qxfer_spu == NULL)
+    return -2;
+
+  if (!target_running ())
+    return -1;
+
+  return (*the_target->qxfer_spu) (annex, readbuf, writebuf, offset, len);
+}
+
+/* Handle qXfer:statictrace:read.  */
+
+static int
+handle_qxfer_statictrace (const char *annex,
+                         gdb_byte *readbuf, const gdb_byte *writebuf,
+                         ULONGEST offset, LONGEST len)
+{
+  ULONGEST nbytes;
+
+  if (writebuf != NULL)
+    return -2;
+
+  if (annex[0] != '\0' || !target_running () || current_traceframe == -1)
+    return -1;
+
+  if (traceframe_read_sdata (current_traceframe, offset,
+                            readbuf, len, &nbytes))
+    return -1;
+  return nbytes;
+}
+
+/* Helper for handle_qxfer_threads.  */
+
+static void
+handle_qxfer_threads_proper (struct buffer *buffer)
+{
+  struct inferior_list_entry *thread;
+
+  buffer_grow_str (buffer, "<threads>\n");
+
+  for (thread = all_threads.head; thread; thread = thread->next)
     {
-      unsigned char *data;
-      int n;
-      CORE_ADDR ofs;
-      unsigned int len;
-      char *annex;
+      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];
 
-      require_running (own_buf);
+      write_ptid (ptid_s, ptid);
 
-      /* Reject any annex; grab the offset and length.  */
-      if (decode_xfer_read (own_buf + 16, &annex, &ofs, &len) < 0
-         || annex[0] != '\0')
+      if (core != -1)
        {
-         strcpy (own_buf, "E00");
-         return;
+         sprintf (core_s, "%d", core);
+         buffer_xml_printf (buffer, "<thread id=\"%s\" core=\"%s\"/>\n",
+                            ptid_s, core_s);
        }
-
-      /* Read one extra byte, as an indicator of whether there is
-        more.  */
-      if (len > PBUFSIZ - 2)
-       len = PBUFSIZ - 2;
-      data = malloc (len + 1);
-      if (data == NULL)
+      else
        {
-         write_enn (own_buf);
-         return;
+         buffer_xml_printf (buffer, "<thread id=\"%s\"/>\n",
+                            ptid_s);
        }
-      n = (*the_target->read_auxv) (ofs, data, len + 1);
-      if (n < 0)
-       write_enn (own_buf);
-      else if (n > len)
-       *new_packet_len_p = write_qxfer_response (own_buf, data, len, 1);
-      else
-       *new_packet_len_p = write_qxfer_response (own_buf, data, n, 0);
+    }
+
+  buffer_grow_str0 (buffer, "</threads>\n");
+}
 
-      free (data);
+/* Handle qXfer:threads:read.  */
 
-      return;
+static int
+handle_qxfer_threads (const char *annex,
+                     gdb_byte *readbuf, const gdb_byte *writebuf,
+                     ULONGEST offset, LONGEST len)
+{
+  static char *result = 0;
+  static unsigned int result_length = 0;
+
+  if (writebuf != NULL)
+    return -2;
+
+  if (!target_running () || annex[0] != '\0')
+    return -1;
+
+  if (offset == 0)
+    {
+      struct buffer buffer;
+      /* When asked for data at offset 0, generate everything and store into
+        'result'.  Successive reads will be served off 'result'.  */
+      if (result)
+       free (result);
+
+      buffer_init (&buffer);
+
+      handle_qxfer_threads_proper (&buffer);
+
+      result = buffer_finish (&buffer);
+      result_length = strlen (result);
+      buffer_free (&buffer);
     }
 
-  if (strncmp ("qXfer:features:read:", own_buf, 20) == 0)
+  if (offset >= result_length)
     {
-      CORE_ADDR ofs;
-      unsigned int len, total_len;
-      const char *document;
-      char *annex;
+      /* We're out of data.  */
+      free (result);
+      result = NULL;
+      result_length = 0;
+      return 0;
+    }
 
-      require_running (own_buf);
+  if (len > result_length - offset)
+    len = result_length - offset;
 
-      /* Grab the annex, offset, and length.  */
-      if (decode_xfer_read (own_buf + 20, &annex, &ofs, &len) < 0)
-       {
-         strcpy (own_buf, "E00");
-         return;
-       }
+  memcpy (readbuf, result + offset, len);
 
-      /* Now grab the correct annex.  */
-      document = get_features_xml (annex);
-      if (document == NULL)
-       {
-         strcpy (own_buf, "E00");
-         return;
-       }
+  return len;
+}
 
-      total_len = strlen (document);
-      if (len > PBUFSIZ - 2)
-       len = PBUFSIZ - 2;
+/* Handle qXfer:traceframe-info:read.  */
 
-      if (ofs > total_len)
-       write_enn (own_buf);
-      else if (len < total_len - ofs)
-       *new_packet_len_p = write_qxfer_response (own_buf, document + ofs,
-                                                 len, 1);
-      else
-       *new_packet_len_p = write_qxfer_response (own_buf, document + ofs,
-                                                 total_len - ofs, 0);
+static int
+handle_qxfer_traceframe_info (const char *annex,
+                             gdb_byte *readbuf, const gdb_byte *writebuf,
+                             ULONGEST offset, LONGEST len)
+{
+  static char *result = 0;
+  static unsigned int result_length = 0;
 
-      return;
+  if (writebuf != NULL)
+    return -2;
+
+  if (!target_running () || annex[0] != '\0' || current_traceframe == -1)
+    return -1;
+
+  if (offset == 0)
+    {
+      struct buffer buffer;
+
+      /* When asked for data at offset 0, generate everything and
+        store into 'result'.  Successive reads will be served off
+        'result'.  */
+      free (result);
+
+      buffer_init (&buffer);
+
+      traceframe_read_info (current_traceframe, &buffer);
+
+      result = buffer_finish (&buffer);
+      result_length = strlen (result);
+      buffer_free (&buffer);
     }
 
-  if (strncmp ("qXfer:libraries:read:", own_buf, 21) == 0)
+  if (offset >= result_length)
     {
-      CORE_ADDR ofs;
-      unsigned int len, total_len;
-      char *document, *p;
-      struct inferior_list_entry *dll_ptr;
-      char *annex;
+      /* We're out of data.  */
+      free (result);
+      result = NULL;
+      result_length = 0;
+      return 0;
+    }
 
-      require_running (own_buf);
+  if (len > result_length - offset)
+    len = result_length - offset;
 
-      /* Reject any annex; grab the offset and length.  */
-      if (decode_xfer_read (own_buf + 21, &annex, &ofs, &len) < 0
-         || annex[0] != '\0')
-       {
-         strcpy (own_buf, "E00");
-         return;
-       }
+  memcpy (readbuf, result + offset, len);
+  return len;
+}
 
-      /* 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);
+/* Handle qXfer:fdpic:read.  */
 
-      document = malloc (total_len);
-      if (document == NULL)
-       {
-         write_enn (own_buf);
-         return;
-       }
-      strcpy (document, "<library-list>\n");
-      p = document + strlen (document);
+static int
+handle_qxfer_fdpic (const char *annex, gdb_byte *readbuf,
+                   const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
+{
+  if (the_target->read_loadmap == NULL)
+    return -2;
+
+  if (!target_running ())
+    return -1;
+
+  return (*the_target->read_loadmap) (annex, offset, readbuf, len);
+}
 
-      for (dll_ptr = all_dlls.head; dll_ptr != NULL; dll_ptr = dll_ptr->next)
+static const struct qxfer qxfer_packets[] =
+  {
+    { "auxv", handle_qxfer_auxv },
+    { "fdpic", handle_qxfer_fdpic},
+    { "features", handle_qxfer_features },
+    { "libraries", handle_qxfer_libraries },
+    { "libraries-svr4", handle_qxfer_libraries_svr4 },
+    { "osdata", handle_qxfer_osdata },
+    { "siginfo", handle_qxfer_siginfo },
+    { "spu", handle_qxfer_spu },
+    { "statictrace", handle_qxfer_statictrace },
+    { "threads", handle_qxfer_threads },
+    { "traceframe-info", handle_qxfer_traceframe_info },
+  };
+
+static int
+handle_qxfer (char *own_buf, int packet_len, int *new_packet_len_p)
+{
+  int i;
+  char *object;
+  char *rw;
+  char *annex;
+  char *offset;
+
+  if (strncmp (own_buf, "qXfer:", 6) != 0)
+    return 0;
+
+  /* Grab the object, r/w and annex.  */
+  if (decode_xfer (own_buf + 6, &object, &rw, &annex, &offset) < 0)
+    {
+      write_enn (own_buf);
+      return 1;
+    }
+
+  for (i = 0;
+       i < sizeof (qxfer_packets) / sizeof (qxfer_packets[0]);
+       i++)
+    {
+      const struct qxfer *q = &qxfer_packets[i];
+
+      if (strcmp (object, q->object) == 0)
        {
-         struct dll_info *dll = (struct dll_info *) dll_ptr;
-         char *name;
+         if (strcmp (rw, "read") == 0)
+           {
+             unsigned char *data;
+             int n;
+             CORE_ADDR ofs;
+             unsigned int len;
+
+             /* Grab the offset and length.  */
+             if (decode_xfer_read (offset, &ofs, &len) < 0)
+               {
+                 write_enn (own_buf);
+                 return 1;
+               }
+
+             /* Read one extra byte, as an indicator of whether there is
+                more.  */
+             if (len > PBUFSIZ - 2)
+               len = PBUFSIZ - 2;
+             data = malloc (len + 1);
+             if (data == NULL)
+               {
+                 write_enn (own_buf);
+                 return 1;
+               }
+             n = (*q->xfer) (annex, data, NULL, ofs, len + 1);
+             if (n == -2)
+               {
+                 free (data);
+                 return 0;
+               }
+             else if (n < 0)
+               write_enn (own_buf);
+             else if (n > len)
+               *new_packet_len_p = write_qxfer_response (own_buf, data, len, 1);
+             else
+               *new_packet_len_p = write_qxfer_response (own_buf, data, n, 0);
+
+             free (data);
+             return 1;
+           }
+         else if (strcmp (rw, "write") == 0)
+           {
+             int n;
+             unsigned int len;
+             CORE_ADDR ofs;
+             unsigned char *data;
+
+             strcpy (own_buf, "E00");
+             data = malloc (packet_len - (offset - own_buf));
+             if (data == NULL)
+               {
+                 write_enn (own_buf);
+                 return 1;
+               }
+             if (decode_xfer_write (offset, packet_len - (offset - own_buf),
+                                    &ofs, &len, data) < 0)
+               {
+                 free (data);
+                 write_enn (own_buf);
+                 return 1;
+               }
+
+             n = (*q->xfer) (annex, NULL, data, ofs, len);
+             if (n == -2)
+               {
+                 free (data);
+                 return 0;
+               }
+             else if (n < 0)
+               write_enn (own_buf);
+             else
+               sprintf (own_buf, "%x", n);
 
-         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);
+             free (data);
+             return 1;
+           }
+
+         return 0;
        }
+    }
 
-      strcpy (p, "</library-list>\n");
+  return 0;
+}
 
-      total_len = strlen (document);
-      if (len > PBUFSIZ - 2)
-       len = PBUFSIZ - 2;
+/* Table used by the crc32 function to calcuate the checksum.  */
 
-      if (ofs > total_len)
-       write_enn (own_buf);
-      else if (len < total_len - ofs)
-       *new_packet_len_p = write_qxfer_response (own_buf, document + ofs,
-                                                 len, 1);
-      else
-       *new_packet_len_p = write_qxfer_response (own_buf, document + ofs,
-                                                 total_len - ofs, 0);
+static unsigned int crc32_table[256] =
+{0, 0};
 
-      free (document);
-      return;
+/* Compute 32 bit CRC from inferior memory.
+
+   On success, return 32 bit CRC.
+   On failure, return (unsigned long long) -1.  */
+
+static unsigned long long
+crc32 (CORE_ADDR base, int len, unsigned int crc)
+{
+  if (!crc32_table[1])
+    {
+      /* Initialize the CRC table and the decoding table.  */
+      int i, j;
+      unsigned int c;
+
+      for (i = 0; i < 256; i++)
+       {
+         for (c = i << 24, j = 8; j > 0; --j)
+           c = c & 0x80000000 ? (c << 1) ^ 0x04c11db7 : (c << 1);
+         crc32_table[i] = c;
+       }
     }
 
-  if (the_target->qxfer_osdata != NULL
-      && strncmp ("qXfer:osdata:read:", own_buf, 18) == 0)
+  while (len--)
     {
-      char *annex;
-      int n;
-      unsigned int len;
-      CORE_ADDR ofs;
-      unsigned char *workbuf;
+      unsigned char byte = 0;
 
-      strcpy (own_buf, "E00");
-      if (decode_xfer_read (own_buf + 18, &annex, &ofs, &len) < 0)
-       return;
-      if (len > PBUFSIZ - 2)
-       len = PBUFSIZ - 2;
-      workbuf = malloc (len + 1);
-      if (!workbuf)
-       return;
-
-      n = (*the_target->qxfer_osdata) (annex, workbuf, NULL, ofs, len + 1);
-      if (n < 0)
-       write_enn (own_buf);
-      else if (n > len)
-       *new_packet_len_p = write_qxfer_response (own_buf, workbuf, len, 1);
-      else
-       *new_packet_len_p = write_qxfer_response (own_buf, workbuf, n, 0);
+      /* Return failure if memory read fails.  */
+      if (read_inferior_memory (base, &byte, 1) != 0)
+       return (unsigned long long) -1;
 
-      free (workbuf);
-      return;
+      crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ byte) & 255];
+      base++;
     }
+  return (unsigned long long) crc;
+}
 
-  if (the_target->qxfer_siginfo != NULL
-      && strncmp ("qXfer:siginfo:read:", own_buf, 19) == 0)
-    {
-      unsigned char *data;
-      int n;
-      CORE_ADDR ofs;
-      unsigned int len;
-      char *annex;
+/* Handle all of the extended 'q' packets.  */
+
+void
+handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
+{
+  static struct inferior_list_entry *thread_ptr;
 
+  /* Reply the current thread id.  */
+  if (strcmp ("qC", own_buf) == 0 && !disable_packet_qC)
+    {
+      ptid_t gdb_id;
       require_running (own_buf);
 
-      /* Reject any annex; grab the offset and length.  */
-      if (decode_xfer_read (own_buf + 19, &annex, &ofs, &len) < 0
-         || annex[0] != '\0')
+      if (!ptid_equal (general_thread, null_ptid)
+         && !ptid_equal (general_thread, minus_one_ptid))
+       gdb_id = general_thread;
+      else
        {
-         strcpy (own_buf, "E00");
-         return;
+         thread_ptr = all_threads.head;
+         gdb_id = thread_to_gdb_id ((struct thread_info *)thread_ptr);
        }
 
-      /* Read one extra byte, as an indicator of whether there is
-        more.  */
-      if (len > PBUFSIZ - 2)
-       len = PBUFSIZ - 2;
-      data = malloc (len + 1);
-      if (!data)
-       return;
-      n = (*the_target->qxfer_siginfo) (annex, data, NULL, ofs, len + 1);
-      if (n < 0)
-       write_enn (own_buf);
-      else if (n > len)
-       *new_packet_len_p = write_qxfer_response (own_buf, data, len, 1);
-      else
-       *new_packet_len_p = write_qxfer_response (own_buf, data, n, 0);
-
-      free (data);
+      sprintf (own_buf, "QC");
+      own_buf += 2;
+      write_ptid (own_buf, gdb_id);
       return;
     }
 
-  if (the_target->qxfer_siginfo != NULL
-      && strncmp ("qXfer:siginfo:write:", own_buf, 20) == 0)
+  if (strcmp ("qSymbol::", own_buf) == 0)
     {
-      char *annex;
-      int n;
-      unsigned int len;
-      CORE_ADDR ofs;
-      unsigned char *data;
+      /* GDB is suggesting new symbols have been loaded.  This may
+        mean a new shared library has been detected as loaded, so
+        take the opportunity to check if breakpoints we think are
+        inserted, still are.  Note that it isn't guaranteed that
+        we'll see this when a shared library is loaded, and nor will
+        we see this for unloads (although breakpoints in unloaded
+        libraries shouldn't trigger), as GDB may not find symbols for
+        the library at all.  We also re-validate breakpoints when we
+        see a second GDB breakpoint for the same address, and or when
+        we access breakpoint shadows.  */
+      validate_breakpoints ();
+
+      if (target_supports_tracepoints ())
+       tracepoint_look_up_symbols ();
 
-      require_running (own_buf);
+      if (target_running () && the_target->look_up_symbols != NULL)
+       (*the_target->look_up_symbols) ();
 
-      strcpy (own_buf, "E00");
-      data = malloc (packet_len - 19);
-      if (!data)
-       return;
-      if (decode_xfer_write (own_buf + 20, packet_len - 20, &annex,
-                            &ofs, &len, data) < 0)
+      strcpy (own_buf, "OK");
+      return;
+    }
+
+  if (!disable_packet_qfThreadInfo)
+    {
+      if (strcmp ("qfThreadInfo", own_buf) == 0)
        {
-         free (data);
+         ptid_t gdb_id;
+
+         require_running (own_buf);
+         thread_ptr = all_threads.head;
+
+         *own_buf++ = 'm';
+         gdb_id = thread_to_gdb_id ((struct thread_info *)thread_ptr);
+         write_ptid (own_buf, gdb_id);
+         thread_ptr = thread_ptr->next;
          return;
        }
 
-      n = (*the_target->qxfer_siginfo)
-       (annex, NULL, (unsigned const char *)data, ofs, len);
-      if (n < 0)
-       write_enn (own_buf);
+      if (strcmp ("qsThreadInfo", own_buf) == 0)
+       {
+         ptid_t gdb_id;
+
+         require_running (own_buf);
+         if (thread_ptr != NULL)
+           {
+             *own_buf++ = 'm';
+             gdb_id = thread_to_gdb_id ((struct thread_info *)thread_ptr);
+             write_ptid (own_buf, gdb_id);
+             thread_ptr = thread_ptr->next;
+             return;
+           }
+         else
+           {
+             sprintf (own_buf, "l");
+             return;
+           }
+       }
+    }
+
+  if (the_target->read_offsets != NULL
+      && strcmp ("qOffsets", own_buf) == 0)
+    {
+      CORE_ADDR text, data;
+
+      require_running (own_buf);
+      if (the_target->read_offsets (&text, &data))
+       sprintf (own_buf, "Text=%lX;Data=%lX;Bss=%lX",
+                (long)text, (long)data, (long)data);
       else
-       sprintf (own_buf, "%x", n);
+       write_enn (own_buf);
 
-      free (data);
       return;
     }
 
@@ -1065,29 +1574,67 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
       && (own_buf[10] == ':' || own_buf[10] == '\0'))
     {
       char *p = &own_buf[10];
+      int gdb_supports_qRelocInsn = 0;
+
+      /* Start processing qSupported packet.  */
+      target_process_qsupported (NULL);
 
       /* Process each feature being provided by GDB.  The first
         feature will follow a ':', and latter features will follow
         ';'.  */
       if (*p == ':')
-       for (p = strtok (p + 1, ";");
-            p != NULL;
-            p = strtok (NULL, ";"))
-         {
-           if (strcmp (p, "multiprocess+") == 0)
-             {
-               /* GDB supports and wants multi-process support if
-                  possible.  */
-               if (target_supports_multi_process ())
-                 multi_process = 1;
-             }
-         }
+       {
+         char **qsupported = NULL;
+         int count = 0;
+         int i;
+
+         /* Two passes, to avoid nested strtok calls in
+            target_process_qsupported.  */
+         for (p = strtok (p + 1, ";");
+              p != NULL;
+              p = strtok (NULL, ";"))
+           {
+             count++;
+             qsupported = xrealloc (qsupported, count * sizeof (char *));
+             qsupported[count - 1] = xstrdup (p);
+           }
+
+         for (i = 0; i < count; i++)
+           {
+             p = qsupported[i];
+             if (strcmp (p, "multiprocess+") == 0)
+               {
+                 /* GDB supports and wants multi-process support if
+                    possible.  */
+                 if (target_supports_multi_process ())
+                   multi_process = 1;
+               }
+             else if (strcmp (p, "qRelocInsn+") == 0)
+               {
+                 /* GDB supports relocate instruction requests.  */
+                 gdb_supports_qRelocInsn = 1;
+               }
+             else
+               target_process_qsupported (p);
+
+             free (p);
+           }
+
+         free (qsupported);
+       }
 
-      sprintf (own_buf, "PacketSize=%x;QPassSignals+", PBUFSIZ - 1);
+      sprintf (own_buf,
+              "PacketSize=%x;QPassSignals+;QProgramSignals+",
+              PBUFSIZ - 1);
 
-      /* We do not have any hook to indicate whether the target backend
-        supports qXfer:libraries:read, so always report it.  */
-      strcat (own_buf, ";qXfer:libraries:read+");
+      if (the_target->qxfer_libraries_svr4 != NULL)
+       strcat (own_buf, ";qXfer:libraries-svr4:read+");
+      else
+       {
+         /* We do not have any hook to indicate whether the non-SVR4 target
+            backend supports qXfer:libraries:read, so always report it.  */
+         strcat (own_buf, ";qXfer:libraries:read+");
+       }
 
       if (the_target->read_auxv != NULL)
        strcat (own_buf, ";qXfer:auxv:read+");
@@ -1098,6 +1645,9 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
       if (the_target->qxfer_siginfo != NULL)
        strcat (own_buf, ";qXfer:siginfo:read+;qXfer:siginfo:write+");
 
+      if (the_target->read_loadmap != NULL)
+       strcat (own_buf, ";qXfer:fdpic:read+");
+
       /* We always report qXfer:features:read, as targets may
         install XML files on a subsequent call to arch_setup.
         If we reported to GDB on startup that we don't support
@@ -1116,6 +1666,33 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
       if (target_supports_non_stop ())
        strcat (own_buf, ";QNonStop+");
 
+      if (target_supports_disable_randomization ())
+       strcat (own_buf, ";QDisableRandomization+");
+
+      strcat (own_buf, ";qXfer:threads:read+");
+
+      if (target_supports_tracepoints ())
+       {
+         strcat (own_buf, ";ConditionalTracepoints+");
+         strcat (own_buf, ";TraceStateVariables+");
+         strcat (own_buf, ";TracepointSource+");
+         strcat (own_buf, ";DisconnectedTracing+");
+         if (gdb_supports_qRelocInsn && target_supports_fast_tracepoints ())
+           strcat (own_buf, ";FastTracepoints+");
+         strcat (own_buf, ";StaticTracepoints+");
+         strcat (own_buf, ";InstallInTrace+");
+         strcat (own_buf, ";qXfer:statictrace:read+");
+         strcat (own_buf, ";qXfer:traceframe-info:read+");
+         strcat (own_buf, ";EnableDisableTracepoints+");
+         strcat (own_buf, ";tracenz+");
+       }
+
+      /* Support target-side breakpoint conditions.  */
+      strcat (own_buf, ";ConditionalBreakpoints+");
+
+      if (target_supports_agent ())
+       strcat (own_buf, ";QAgent+");
+
       return;
     }
 
@@ -1172,7 +1749,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
 
       if (err == 0)
        {
-         sprintf (own_buf, "%llx", address);
+         strcpy (own_buf, paddress(address));
          return;
        }
       else if (err > 0)
@@ -1184,6 +1761,29 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
       /* Otherwise, pretend we do not understand this packet.  */
     }
 
+  /* Windows OS Thread Information Block address support.  */
+  if (the_target->get_tib_address != NULL
+      && strncmp ("qGetTIBAddr:", own_buf, 12) == 0)
+    {
+      char *annex;
+      int n;
+      CORE_ADDR tlb;
+      ptid_t ptid = read_ptid (own_buf + 12, &annex);
+
+      n = (*the_target->get_tib_address) (ptid, &tlb);
+      if (n == 1)
+       {
+         strcpy (own_buf, paddress(tlb));
+         return;
+       }
+      else if (n == 0)
+       {
+         write_enn (own_buf);
+         return;
+       }
+      return;
+    }
+
   /* Handle "monitor" commands.  */
   if (strncmp ("qRcmd,", own_buf, 6) == 0)
     {
@@ -1206,42 +1806,17 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
 
       write_ok (own_buf);
 
-      if (strcmp (mon, "set debug 1") == 0)
-       {
-         debug_threads = 1;
-         monitor_output ("Debug output enabled.\n");
-       }
-      else if (strcmp (mon, "set debug 0") == 0)
-       {
-         debug_threads = 0;
-         monitor_output ("Debug output disabled.\n");
-       }
-      else if (strcmp (mon, "set remote-debug 1") == 0)
-       {
-         remote_debug = 1;
-         monitor_output ("Protocol debug output enabled.\n");
-       }
-      else if (strcmp (mon, "set remote-debug 0") == 0)
-       {
-         remote_debug = 0;
-         monitor_output ("Protocol debug output disabled.\n");
-       }
-      else if (strcmp (mon, "help") == 0)
-       monitor_show_help ();
-      else if (strcmp (mon, "exit") == 0)
-       exit_requested = 1;
-      else
-       {
-         monitor_output ("Unknown monitor command.\n\n");
-         monitor_show_help ();
-         write_enn (own_buf);
-       }
+      if (the_target->handle_monitor_command == NULL
+         || (*the_target->handle_monitor_command) (mon) == 0)
+       /* Default processing.  */
+       handle_monitor_command (mon, own_buf);
 
       free (mon);
       return;
     }
 
-  if (strncmp ("qSearch:memory:", own_buf, sizeof ("qSearch:memory:") - 1) == 0)
+  if (strncmp ("qSearch:memory:", own_buf,
+              sizeof ("qSearch:memory:") - 1) == 0)
     {
       require_running (own_buf);
       handle_search_memory (own_buf, packet_len);
@@ -1275,11 +1850,46 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
       return;
     }
 
+  if (strncmp ("qCRC:", own_buf, 5) == 0)
+    {
+      /* CRC check (compare-section).  */
+      char *comma;
+      CORE_ADDR base;
+      int len;
+      unsigned long long crc;
+
+      require_running (own_buf);
+      base = strtoul (own_buf + 5, &comma, 16);
+      if (*comma++ != ',')
+       {
+         write_enn (own_buf);
+         return;
+       }
+      len = strtoul (comma, NULL, 16);
+      crc = crc32 (base, len, 0xffffffff);
+      /* Check for memory failure.  */
+      if (crc == (unsigned long long) -1)
+       {
+         write_enn (own_buf);
+         return;
+       }
+      sprintf (own_buf, "C%lx", (unsigned long) crc);
+      return;
+    }
+
+  if (handle_qxfer (own_buf, packet_len, new_packet_len_p))
+    return;
+
+  if (target_supports_tracepoints () && handle_tracepoint_query (own_buf))
+    return;
+
   /* Otherwise we didn't know what packet it was.  Say we didn't
      understand it.  */
   own_buf[0] = 0;
 }
 
+static void gdb_wants_all_threads_stopped (void);
+
 /* Parse vCont packets.  */
 void
 handle_v_cont (char *own_buf)
@@ -1362,9 +1972,13 @@ handle_v_cont (char *own_buf)
   if (i < n)
     resume_info[i] = default_action;
 
-  /* Still used in occasional places in the backend.  */
+  /* `cont_thread' is still used in occasional places in the backend,
+     to implement single-thread scheduler-locking.  Doesn't make sense
+     to set it if we see a stop request, or any form of wildcard
+     vCont.  */
   if (n == 1
-      && !ptid_equal (resume_info[0].thread, minus_one_ptid)
+      && !(ptid_equal (resume_info[0].thread, minus_one_ptid)
+          || ptid_get_lwp (resume_info[0].thread) == -1)
       && resume_info[0].kind != resume_stop)
     cont_thread = resume_info[0].thread;
   else
@@ -1383,8 +1997,22 @@ handle_v_cont (char *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_status = last_status;
+
+      /* From the client's perspective, all-stop mode always stops all
+        threads implicitly (and the target backend has already done
+        so by now).  Tag all threads as "want-stopped", so we don't
+        resume them implicitly without the client telling us to.  */
+      gdb_wants_all_threads_stopped ();
       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)));
     }
   return;
 
@@ -1479,16 +2107,16 @@ handle_v_run (char *own_buf)
 
       if (program_argv == NULL)
        {
-         /* FIXME: new_argv memory leak */
          write_enn (own_buf);
+         freeargv (new_argv);
          return 0;
        }
 
       new_argv[0] = strdup (program_argv[0]);
       if (new_argv[0] == NULL)
        {
-         /* FIXME: new_argv memory leak */
          write_enn (own_buf);
+         freeargv (new_argv);
          return 0;
        }
     }
@@ -1592,7 +2220,7 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len)
 
   if (strncmp (own_buf, "vAttach;", 8) == 0)
     {
-      if (!multi_process && target_running ())
+      if ((!extended_protocol || !multi_process) && target_running ())
        {
          fprintf (stderr, "Already debugging a process\n");
          write_enn (own_buf);
@@ -1604,7 +2232,7 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len)
 
   if (strncmp (own_buf, "vRun;", 5) == 0)
     {
-      if (!multi_process && target_running ())
+      if ((!extended_protocol || !multi_process) && target_running ())
        {
          fprintf (stderr, "Already debugging a process\n");
          write_enn (own_buf);
@@ -1641,7 +2269,7 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len)
 /* Resume inferior and wait for another event.  In non-stop mode,
    don't really wait here, but return immediatelly to the event
    loop.  */
-void
+static void
 myresume (char *own_buf, int step, int sig)
 {
   struct thread_resume resume_info[2];
@@ -1683,8 +2311,20 @@ myresume (char *own_buf, int step, int sig)
   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)));
     }
 }
 
@@ -1694,31 +2334,82 @@ myresume (char *own_buf, int step, int sig)
 static int
 queue_stop_reply_callback (struct inferior_list_entry *entry, void *arg)
 {
-  int pid = * (int *) arg;
+  struct thread_info *thread = (struct thread_info *) entry;
 
-  if (pid == -1
-      || ptid_get_pid (entry->id) == pid)
+  /* 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)
+    {
+      /* Pass the last stop reply back to GDB, but don't notify
+        yet.  */
+      queue_stop_reply (entry->id, &thread->last_status);
+    }
+  else
     {
-      struct target_waitstatus status;
+      if (thread_stopped (thread))
+       {
+         if (debug_threads)
+           fprintf (stderr,
+                    "Reporting thread %s as already stopped with %s\n",
+                    target_pid_to_str (entry->id),
+                    target_waitstatus_to_string (&thread->last_status));
 
-      status.kind = TARGET_WAITKIND_STOPPED;
-      status.value.sig = TARGET_SIGNAL_TRAP;
+         gdb_assert (thread->last_status.kind != TARGET_WAITKIND_IGNORE);
 
-      /* Pass the last stop reply back to GDB, but don't notify.  */
-      queue_stop_reply (entry->id, &status);
+         /* Pass the last stop reply back to GDB, but don't notify
+            yet.  */
+         queue_stop_reply (entry->id, &thread->last_status);
+       }
     }
 
   return 0;
 }
 
+/* Set this inferior threads's state as "want-stopped".  We won't
+   resume this thread until the client gives us another action for
+   it.  */
+
+static void
+gdb_wants_thread_stopped (struct inferior_list_entry *entry)
+{
+  struct thread_info *thread = (struct thread_info *) entry;
+
+  thread->last_resume_kind = resume_stop;
+
+  if (thread->last_status.kind == TARGET_WAITKIND_IGNORE)
+    {
+      /* Most threads are stopped implicitly (all-stop); tag that with
+        signal 0.  */
+      thread->last_status.kind = TARGET_WAITKIND_STOPPED;
+      thread->last_status.value.sig = TARGET_SIGNAL_0;
+    }
+}
+
+/* Set all threads' states as "want-stopped".  */
+
+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;
+}
+
 /* Status handler for the '?' packet.  */
 
 static void
 handle_status (char *own_buf)
 {
-  struct target_waitstatus status;
-  status.kind = TARGET_WAITKIND_STOPPED;
-  status.value.sig = TARGET_SIGNAL_TRAP;
+  /* GDB is connected, don't forward events to the target anymore.  */
+  for_each_inferior (&all_processes, gdb_reattached_process);
 
   /* 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
@@ -1726,9 +2417,8 @@ handle_status (char *own_buf)
 
   if (non_stop)
     {
-      int pid = -1;
-      discard_queued_stop_replies (pid);
-      find_inferior (&all_threads, queue_stop_reply_callback, &pid);
+      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
         stopped thread, which is the same handling of the vStopped
@@ -1737,9 +2427,19 @@ handle_status (char *own_buf)
     }
   else
     {
+      pause_all (0);
+      stabilize_threads ();
+      gdb_wants_all_threads_stopped ();
+
       if (all_threads.head)
-       prepare_resume_reply (own_buf,
-                             all_threads.head->id, &status);
+       {
+         struct target_waitstatus status;
+
+         status.kind = TARGET_WAITKIND_STOPPED;
+         status.value.sig = TARGET_SIGNAL_TRAP;
+         prepare_resume_reply (own_buf,
+                               all_threads.head->id, &status);
+       }
       else
        strcpy (own_buf, "W00");
     }
@@ -1749,8 +2449,9 @@ static void
 gdbserver_version (void)
 {
   printf ("GNU gdbserver %s%s\n"
-         "Copyright (C) 2009 Free Software Foundation, Inc.\n"
-         "gdbserver is free software, covered by the GNU General Public License.\n"
+         "Copyright (C) 2012 Free Software Foundation, Inc.\n"
+         "gdbserver is free software, covered by the "
+         "GNU General Public License.\n"
          "This gdbserver was configured as \"%s\"\n",
          PKGVERSION, version, host_name);
 }
@@ -1769,7 +2470,9 @@ gdbserver_usage (FILE *stream)
           "  --debug               Enable general debugging output.\n"
           "  --remote-debug        Enable remote protocol debugging output.\n"
           "  --version             Display version information and exit.\n"
-          "  --wrapper WRAPPER --  Run WRAPPER to start new programs.\n");
+          "  --wrapper WRAPPER --  Run WRAPPER to start new programs.\n"
+          "  --once                Exit after the first connection has "
+                                                                 "closed.\n");
   if (REPORT_BUGS_TO[0] && stream == stdout)
     fprintf (stream, "Report bugs to \"%s\".\n", REPORT_BUGS_TO);
 }
@@ -1781,7 +2484,8 @@ gdbserver_show_disableable (FILE *stream)
           "  vCont       \tAll vCont packets\n"
           "  qC          \tQuerying the current thread\n"
           "  qfThreadInfo\tThread listing\n"
-          "  Tthread     \tPassing the thread specifier in the T stop reply packet\n"
+          "  Tthread     \tPassing the thread specifier in the "
+          "T stop reply packet\n"
           "  threads     \tAll of the above\n");
 }
 
@@ -1893,17 +2597,6 @@ detach_or_kill_for_exit (void)
   for_each_inferior (&all_processes, detach_or_kill_inferior_callback);
 }
 
-static void
-join_inferiors_callback (struct inferior_list_entry *entry)
-{
-  struct process_info *process = (struct process_info *) entry;
-
-  /* If we are attached, then we can exit.  Otherwise, we need to hang
-     around doing nothing, until the child is gone.  */
-  if (!process->attached)
-    join_inferior (ptid_get_pid (process->head.id));
-}
-
 int
 main (int argc, char *argv[])
 {
@@ -1992,6 +2685,19 @@ main (int argc, char *argv[])
                }
            }
        }
+      else if (strcmp (*next_arg, "-") == 0)
+       {
+         /* "-" specifies a stdio connection and is a form of port
+            specification.  */
+         *next_arg = STDIO_CONNECTION_NAME;
+         break;
+       }
+      else if (strcmp (*next_arg, "--disable-randomization") == 0)
+       disable_randomization = 1;
+      else if (strcmp (*next_arg, "--no-disable-randomization") == 0)
+       disable_randomization = 0;
+      else if (strcmp (*next_arg, "--once") == 0)
+       run_once = 1;
       else
        {
          fprintf (stderr, "Unknown argument: %s\n", *next_arg);
@@ -2016,6 +2722,12 @@ main (int argc, char *argv[])
       exit (1);
     }
 
+  /* 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
+     start_inferior.  */
+  remote_prepare (port);
+
   bad_attach = 0;
   pid = 0;
 
@@ -2041,9 +2753,10 @@ main (int argc, char *argv[])
       exit (1);
     }
 
-  initialize_inferiors ();
   initialize_async_io ();
   initialize_low ();
+  if (target_supports_tracepoints ())
+    initialize_tracepoint ();
 
   own_buf = xmalloc (PBUFSIZ + 1);
   mem_buf = xmalloc (PBUFSIZ);
@@ -2086,7 +2799,14 @@ main (int argc, char *argv[])
 
   if (setjmp (toplevel))
     {
-      detach_or_kill_for_exit ();
+      /* If something fails and longjmps while detaching or killing
+        inferiors, we'd end up here again, stuck in an infinite loop
+        trap.  Be sure that if that happens, we exit immediately
+        instead.  */
+      if (setjmp (toplevel) == 0)
+       detach_or_kill_for_exit ();
+      else
+       fprintf (stderr, "Detach or kill failed.  Exiting\n");
       exit (1);
     }
 
@@ -2106,7 +2826,8 @@ main (int argc, char *argv[])
     {
       noack_mode = 0;
       multi_process = 0;
-      non_stop = 0;
+      /* Be sure we're out of tfind mode.  */
+      current_traceframe = -1;
 
       remote_open (port);
 
@@ -2121,7 +2842,7 @@ main (int argc, char *argv[])
        }
 
       /* Wait for events.  This will return when all event sources are
-        removed from the event loop. */
+        removed from the event loop.  */
       start_event_loop ();
 
       /* If an exit was requested (using the "monitor exit" command),
@@ -2129,15 +2850,93 @@ main (int argc, char *argv[])
         getpkt to fail; close the connection and reopen it at the
         top of the loop.  */
 
-      if (exit_requested)
+      if (exit_requested || run_once)
        {
-         detach_or_kill_for_exit ();
-         exit (0);
+         /* If something fails and longjmps while detaching or
+            killing inferiors, we'd end up here again, stuck in an
+            infinite loop trap.  Be sure that if that happens, we
+            exit immediately instead.  */
+         if (setjmp (toplevel) == 0)
+           {
+             detach_or_kill_for_exit ();
+             exit (0);
+           }
+         else
+           {
+             fprintf (stderr, "Detach or kill failed.  Exiting\n");
+             exit (1);
+           }
        }
-      else
-       fprintf (stderr, "Remote side has terminated connection.  "
-                "GDBserver will reopen the connection.\n");
+
+      fprintf (stderr,
+              "Remote side has terminated connection.  "
+              "GDBserver will reopen the connection.\n");
+
+      if (tracing)
+       {
+         if (disconnected_tracing)
+           {
+             /* Try to enable non-stop/async mode, so we we can both
+                wait for an async socket accept, and handle async
+                target events simultaneously.  There's also no point
+                either in having the target always stop all threads,
+                when we're going to pass signals down without
+                informing GDB.  */
+             if (!non_stop)
+               {
+                 if (start_non_stop (1))
+                   non_stop = 1;
+
+                 /* Detaching implicitly resumes all threads; simply
+                    disconnecting does not.  */
+               }
+           }
+         else
+           {
+             fprintf (stderr,
+                      "Disconnected tracing disabled; stopping trace run.\n");
+             stop_tracing ();
+           }
+       }
+    }
+}
+
+/* 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.  */
+
+static void
+process_point_options (CORE_ADDR point_addr, char **packet)
+{
+  char *dataptr = *packet;
+
+  /* Check if data has the correct format.  */
+  if (*dataptr != ';')
+    return;
+
+  dataptr++;
+
+  while (*dataptr)
+    {
+      switch (*dataptr)
+       {
+         case 'X':
+           /* Conditional expression.  */
+           if (remote_debug)
+             fprintf (stderr, "Found breakpoint condition.\n");
+           add_breakpoint_condition (point_addr, &dataptr);
+           break;
+         default:
+           /* Unrecognized token, just skip it.  */
+           fprintf (stderr, "Unknown token %c, ignoring.\n",
+                    *dataptr);
+       }
+
+      /* Skip tokens until we find one that we recognize.  */
+      while (*dataptr && *dataptr != 'X' && *dataptr != ';')
+       dataptr++;
     }
+  *packet = dataptr;
 }
 
 /* Event loop callback that handles a serial event.  The first byte in
@@ -2145,13 +2944,14 @@ main (int argc, char *argv[])
    a brisk pace, so we read the rest of the packet with a blocking
    getpkt call.  */
 
-static void
+static int
 process_serial_event (void)
 {
   char ch;
   int i = 0;
   int signal;
   unsigned int len;
+  int res;
   CORE_ADDR mem_addr;
   int pid;
   unsigned char sig;
@@ -2171,9 +2971,9 @@ process_serial_event (void)
   packet_len = getpkt (own_buf);
   if (packet_len <= 0)
     {
-      target_async (0);
       remote_close ();
-      return;
+      /* Force an event loop break.  */
+      return -1;
     }
   response_needed = 1;
 
@@ -2199,7 +2999,49 @@ process_serial_event (void)
        pid =
          ptid_get_pid (((struct inferior_list_entry *) current_inferior)->id);
 
+      if (tracing && disconnected_tracing)
+       {
+         struct thread_resume resume_info;
+         struct process_info *process = find_process_pid (pid);
+
+         if (process == NULL)
+           {
+             write_enn (own_buf);
+             break;
+           }
+
+         fprintf (stderr,
+                  "Disconnected tracing in effect, "
+                  "leaving gdbserver attached to the process\n");
+
+         /* Make sure we're in non-stop/async mode, so we we can both
+            wait for an async socket accept, and handle async target
+            events simultaneously.  There's also no point either in
+            having the target stop all threads, when we're going to
+            pass signals down without informing GDB.  */
+         if (!non_stop)
+           {
+             if (debug_threads)
+               fprintf (stderr, "Forcing non-stop mode\n");
+
+             non_stop = 1;
+             start_non_stop (1);
+           }
+
+         process->gdb_detached = 1;
+
+         /* Detaching implicitly resumes all threads.  */
+         resume_info.thread = minus_one_ptid;
+         resume_info.kind = resume_continue;
+         resume_info.sig = 0;
+         (*the_target->resume) (&resume_info, 1);
+
+         write_ok (own_buf);
+         break; /* from switch/case */
+       }
+
       fprintf (stderr, "Detaching from process %d\n", pid);
+      stop_tracing ();
       if (detach_inferior (pid) != 0)
        write_enn (own_buf);
       else
@@ -2224,8 +3066,7 @@ process_serial_event (void)
              /* If we are attached, then we can exit.  Otherwise, we
                 need to hang around doing nothing, until the child is
                 gone.  */
-             for_each_inferior (&all_processes,
-                                join_inferiors_callback);
+             join_inferior (pid);
              exit (0);
            }
        }
@@ -2297,8 +3138,6 @@ process_serial_event (void)
            }
          else if (own_buf[1] == 'c')
            cont_thread = thread_id;
-         else if (own_buf[1] == 's')
-           step_thread = thread_id;
 
          write_ok (own_buf);
        }
@@ -2311,27 +3150,53 @@ process_serial_event (void)
       break;
     case 'g':
       require_running (own_buf);
-      set_desired_inferior (1);
-      registers_to_string (own_buf);
+      if (current_traceframe >= 0)
+       {
+         struct regcache *regcache = new_register_cache ();
+
+         if (fetch_traceframe_registers (current_traceframe,
+                                         regcache, -1) == 0)
+           registers_to_string (regcache, own_buf);
+         else
+           write_enn (own_buf);
+         free_register_cache (regcache);
+       }
+      else
+       {
+         struct regcache *regcache;
+
+         set_desired_inferior (1);
+         regcache = get_thread_regcache (current_inferior, 1);
+         registers_to_string (regcache, own_buf);
+       }
       break;
     case 'G':
       require_running (own_buf);
-      set_desired_inferior (1);
-      registers_from_string (&own_buf[1]);
-      write_ok (own_buf);
+      if (current_traceframe >= 0)
+       write_enn (own_buf);
+      else
+       {
+         struct regcache *regcache;
+
+         set_desired_inferior (1);
+         regcache = get_thread_regcache (current_inferior, 1);
+         registers_from_string (regcache, &own_buf[1]);
+         write_ok (own_buf);
+       }
       break;
     case 'm':
       require_running (own_buf);
       decode_m_packet (&own_buf[1], &mem_addr, &len);
-      if (read_inferior_memory (mem_addr, mem_buf, len) == 0)
-       convert_int_to_ascii (mem_buf, own_buf, len);
-      else
+      res = gdb_read_memory (mem_addr, mem_buf, len);
+      if (res < 0)
        write_enn (own_buf);
+      else
+       convert_int_to_ascii (mem_buf, own_buf, res);
       break;
     case 'M':
       require_running (own_buf);
-      decode_M_packet (&own_buf[1], &mem_addr, &len, mem_buf);
-      if (write_inferior_memory (mem_addr, mem_buf, len) == 0)
+      decode_M_packet (&own_buf[1], &mem_addr, &len, &mem_buf);
+      if (gdb_write_memory (mem_addr, mem_buf, len) == 0)
        write_ok (own_buf);
       else
        write_enn (own_buf);
@@ -2339,8 +3204,8 @@ process_serial_event (void)
     case 'X':
       require_running (own_buf);
       if (decode_X_packet (&own_buf[1], packet_len - 1,
-                          &mem_addr, &len, mem_buf) < 0
-         || write_inferior_memory (mem_addr, mem_buf, len) != 0)
+                          &mem_addr, &len, &mem_buf) < 0
+         || gdb_write_memory (mem_addr, mem_buf, len) != 0)
        write_enn (own_buf);
       else
        write_ok (own_buf);
@@ -2396,7 +3261,22 @@ process_serial_event (void)
          case '4': /* access watchpoint */
            require_running (own_buf);
            if (insert && the_target->insert_point != NULL)
-             res = (*the_target->insert_point) (type, addr, len);
+             {
+               /* Insert the breakpoint.  If it is already inserted, nothing
+                  will take place.  */
+               res = (*the_target->insert_point) (type, addr, len);
+
+               /* GDB may have sent us a list of *point parameters to be
+                  evaluated on the target's side.  Read such list here.  If we
+                  already have a list of parameters, GDB is telling us to drop
+                  that list and use this one instead.  */
+               if (!res && (type == '0' || type == '1'))
+                 {
+                   /* Remove previous conditions.  */
+                   clear_gdb_breakpoint_conditions (addr);
+                   process_point_options (addr, &dataptr);
+                 }
+             }
            else if (!insert && the_target->remove_point != NULL)
              res = (*the_target->remove_point) (type, addr, len);
            break;
@@ -2418,7 +3298,7 @@ process_serial_event (void)
       if (!target_running ())
        /* The packet we received doesn't make sense - but we can't
           reply to it, either.  */
-       return;
+       return 0;
 
       fprintf (stderr, "Killing all inferiors\n");
       for_each_inferior (&all_processes, kill_inferior_callback);
@@ -2429,13 +3309,11 @@ process_serial_event (void)
        {
          last_status.kind = TARGET_WAITKIND_EXITED;
          last_status.value.sig = TARGET_SIGNAL_KILL;
-         return;
+         return 0;
        }
       else
-       {
-         exit (0);
-         break;
-       }
+       exit (0);
+
     case 'T':
       {
        ptid_t gdb_id, thread_id;
@@ -2476,7 +3354,7 @@ process_serial_event (void)
              last_status.kind = TARGET_WAITKIND_EXITED;
              last_status.value.sig = TARGET_SIGNAL_KILL;
            }
-         return;
+         return 0;
        }
       else
        {
@@ -2517,27 +3395,35 @@ process_serial_event (void)
          exit (0);
        }
     }
+
+  if (exit_requested)
+    return -1;
+
+  return 0;
 }
 
 /* Event-loop callback for serial events.  */
 
-void
+int
 handle_serial_event (int err, gdb_client_data client_data)
 {
   if (debug_threads)
     fprintf (stderr, "handling possible serial event\n");
 
   /* Really handle it.  */
-  process_serial_event ();
+  if (process_serial_event () < 0)
+    return -1;
 
   /* Be sure to not change the selected inferior behind GDB's back.
      Important in the non-stop mode asynchronous protocol.  */
   set_desired_inferior (1);
+
+  return 0;
 }
 
 /* Event-loop callback for target events.  */
 
-void
+int
 handle_target_event (int err, gdb_client_data client_data)
 {
   if (debug_threads)
@@ -2548,11 +3434,66 @@ handle_target_event (int err, gdb_client_data client_data)
 
   if (last_status.kind != TARGET_WAITKIND_IGNORE)
     {
-      /* Something interesting.  Tell GDB about it.  */
-      push_event (last_ptid, &last_status);
+      int pid = ptid_get_pid (last_ptid);
+      struct process_info *process = find_process_pid (pid);
+      int forward_event = !gdb_connected () || process->gdb_detached;
+
+      if (last_status.kind == TARGET_WAITKIND_EXITED
+         || last_status.kind == TARGET_WAITKIND_SIGNALLED)
+       {
+         mark_breakpoints_out (process);
+         mourn_inferior (process);
+       }
+      else
+       {
+         /* We're reporting this thread as stopped.  Update its
+            "want-stopped" state to what the client wants, until it
+            gets a new resume action.  */
+         current_inferior->last_resume_kind = resume_stop;
+         current_inferior->last_status = last_status;
+       }
+
+      if (forward_event)
+       {
+         if (!target_running ())
+           {
+             /* The last process exited.  We're done.  */
+             exit (0);
+           }
+
+         if (last_status.kind == TARGET_WAITKIND_STOPPED)
+           {
+             /* A thread stopped with a signal, but gdb isn't
+                connected to handle it.  Pass it down to the
+                inferior, as if it wasn't being traced.  */
+             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));
+
+             resume_info.thread = last_ptid;
+             resume_info.kind = resume_continue;
+             resume_info.sig = target_signal_to_host (last_status.value.sig);
+             (*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));
+       }
+      else
+       {
+         /* Something interesting.  Tell GDB about it.  */
+         push_event (last_ptid, &last_status);
+       }
     }
 
   /* Be sure to not change the selected inferior behind GDB's back.
      Important in the non-stop mode asynchronous protocol.  */
   set_desired_inferior (1);
+
+  return 0;
 }
This page took 0.09524 seconds and 4 git commands to generate.