]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gdb/gdbserver/remote-utils.c
gdbserver: fix various warnings
[thirdparty/binutils-gdb.git] / gdb / gdbserver / remote-utils.c
index e82c967b4d915be7a7962d765d8e7b9930853407..40bd373aae1e1f6afd8a5f2af25495e8cd252005 100644 (file)
@@ -1,6 +1,5 @@
 /* Remote utility routines for the remote server for GDB.
-   Copyright (C) 1986, 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-   2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 1986-2016 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 
 #include "server.h"
 #include "terminal.h"
-#include <stdio.h>
-#include <string.h>
+#include "target.h"
+#include "gdbthread.h"
+#include "tdesc.h"
+#include "dll.h"
+#include "rsp-low.h"
+#include <ctype.h>
 #if HAVE_SYS_IOCTL_H
 #include <sys/ioctl.h>
 #endif
 #if HAVE_FCNTL_H
 #include <fcntl.h>
 #endif
-#include <sys/time.h>
-#if HAVE_UNISTD_H
+#include "gdb_sys_time.h"
 #include <unistd.h>
-#endif
 #if HAVE_ARPA_INET_H
 #include <arpa/inet.h>
 #endif
 #include <sys/stat.h>
-#if HAVE_ERRNO_H
-#include <errno.h>
-#endif
 
 #if USE_WIN32API
-#include <winsock.h>
+#include <winsock2.h>
 #endif
 
+#if __QNX__
+#include <sys/iomgr.h>
+#endif /* __QNX__ */
+
 #ifndef HAVE_SOCKLEN_T
 typedef int socklen_t;
 #endif
 
+#ifndef IN_PROCESS_AGENT
+
 #if USE_WIN32API
 # define INVALID_DESCRIPTOR INVALID_SOCKET
 #else
 # define INVALID_DESCRIPTOR -1
 #endif
 
+/* Extra value for readchar_callback.  */
+enum {
+  /* The callback is currently not scheduled.  */
+  NOT_SCHEDULED = -1
+};
+
+/* Status of the readchar callback.
+   Either NOT_SCHEDULED or the callback id.  */
+static int readchar_callback = NOT_SCHEDULED;
+
+static int readchar (void);
+static void reset_readchar (void);
+static void reschedule (void);
+
 /* A cache entry for a successfully looked-up symbol.  */
 struct sym_cache
 {
-  const char *name;
+  char *name;
   CORE_ADDR addr;
   struct sym_cache *next;
 };
 
-/* The symbol cache.  */
-static struct sym_cache *symbol_cache;
-
-/* If this flag has been set, assume cache misses are
-   failures.  */
-int all_symbols_looked_up;
-
 int remote_debug = 0;
 struct ui_file *gdb_stdlog;
 
-static int remote_desc = INVALID_DESCRIPTOR;
+static int remote_is_stdio = 0;
+
+static gdb_fildes_t remote_desc = INVALID_DESCRIPTOR;
+static gdb_fildes_t listen_desc = INVALID_DESCRIPTOR;
 
 /* FIXME headerize? */
 extern int using_threads;
 extern int debug_threads;
 
+/* If true, then GDB has requested noack mode.  */
+int noack_mode = 0;
+/* If true, then we tell GDB to use noack mode by default.  */
+int transport_is_reliable = 0;
+
 #ifdef USE_WIN32API
 # define read(fd, buf, len) recv (fd, (char *) buf, len, 0)
 # define write(fd, buf, len) send (fd, (char *) buf, len, 0)
 #endif
 
-/* Open a connection to a remote debugger.
-   NAME is the filename used for communication.  */
+int
+gdb_connected (void)
+{
+  return remote_desc != INVALID_DESCRIPTOR;
+}
 
-void
-remote_open (char *name)
+/* Return true if the remote connection is over stdio.  */
+
+int
+remote_connection_is_stdio (void)
+{
+  return remote_is_stdio;
+}
+
+static void
+enable_async_notification (int fd)
 {
 #if defined(F_SETFL) && defined (FASYNC)
   int save_fcntl_flags;
+
+  save_fcntl_flags = fcntl (fd, F_GETFL, 0);
+  fcntl (fd, F_SETFL, save_fcntl_flags | FASYNC);
+#if defined (F_SETOWN)
+  fcntl (fd, F_SETOWN, getpid ());
+#endif
+#endif
+}
+
+static int
+handle_accept_event (int err, gdb_client_data client_data)
+{
+  struct sockaddr_in sockaddr;
+  socklen_t tmp;
+
+  if (debug_threads)
+    debug_printf ("handling possible accept event\n");
+
+  tmp = sizeof (sockaddr);
+  remote_desc = accept (listen_desc, (struct sockaddr *) &sockaddr, &tmp);
+  if (remote_desc == -1)
+    perror_with_name ("Accept failed");
+
+  /* Enable TCP keep alive process. */
+  tmp = 1;
+  setsockopt (remote_desc, SOL_SOCKET, SO_KEEPALIVE,
+             (char *) &tmp, sizeof (tmp));
+
+  /* Tell TCP not to delay small packets.  This greatly speeds up
+     interactive response. */
+  tmp = 1;
+  setsockopt (remote_desc, IPPROTO_TCP, TCP_NODELAY,
+             (char *) &tmp, sizeof (tmp));
+
+#ifndef USE_WIN32API
+  signal (SIGPIPE, SIG_IGN);   /* If we don't do this, then gdbserver simply
+                                  exits when the remote side dies.  */
 #endif
+
+  if (run_once)
+    {
+#ifndef USE_WIN32API
+      close (listen_desc);             /* No longer need this */
+#else
+      closesocket (listen_desc);       /* No longer need this */
+#endif
+    }
+
+  /* Even if !RUN_ONCE no longer notice new connections.  Still keep the
+     descriptor open for add_file_handler to wait for a new connection.  */
+  delete_file_handler (listen_desc);
+
+  /* Convert IP address to string.  */
+  fprintf (stderr, "Remote debugging from host %s\n",
+          inet_ntoa (sockaddr.sin_addr));
+
+  enable_async_notification (remote_desc);
+
+  /* Register the event loop handler.  */
+  add_file_handler (remote_desc, handle_serial_event, NULL);
+
+  /* We have a new GDB connection now.  If we were disconnected
+     tracing, there's a window where the target could report a stop
+     event to the event loop, and since we have a connection now, we'd
+     try to send vStopped notifications to GDB.  But, don't do that
+     until GDB as selected all-stop/non-stop, and has queried the
+     threads' status ('?').  */
+  target_async (0);
+
+  return 0;
+}
+
+/* Prepare for a later connection to a remote debugger.
+   NAME is the filename used for communication.  */
+
+void
+remote_prepare (char *name)
+{
   char *port_str;
+#ifdef USE_WIN32API
+  static int winsock_initialized;
+#endif
+  int port;
+  struct sockaddr_in sockaddr;
+  socklen_t tmp;
+  char *port_end;
+
+  remote_is_stdio = 0;
+  if (strcmp (name, STDIO_CONNECTION_NAME) == 0)
+    {
+      /* We need to record fact that we're using stdio sooner than the
+        call to remote_open so start_inferior knows the connection is
+        via stdio.  */
+      remote_is_stdio = 1;
+      transport_is_reliable = 1;
+      return;
+    }
 
   port_str = strchr (name, ':');
   if (port_str == NULL)
     {
+      transport_is_reliable = 0;
+      return;
+    }
+
+  port = strtoul (port_str + 1, &port_end, 10);
+  if (port_str[1] == '\0' || *port_end != '\0')
+    error ("Bad port argument: %s", name);
+
 #ifdef USE_WIN32API
-      error ("Only <host>:<port> is supported on this platform.");
-#else
+  if (!winsock_initialized)
+    {
+      WSADATA wsad;
+
+      WSAStartup (MAKEWORD (1, 0), &wsad);
+      winsock_initialized = 1;
+    }
+#endif
+
+  listen_desc = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
+  if (listen_desc == -1)
+    perror_with_name ("Can't open socket");
+
+  /* Allow rapid reuse of this port. */
+  tmp = 1;
+  setsockopt (listen_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp,
+             sizeof (tmp));
+
+  sockaddr.sin_family = PF_INET;
+  sockaddr.sin_port = htons (port);
+  sockaddr.sin_addr.s_addr = INADDR_ANY;
+
+  if (bind (listen_desc, (struct sockaddr *) &sockaddr, sizeof (sockaddr))
+      || listen (listen_desc, 1))
+    perror_with_name ("Can't bind address");
+
+  transport_is_reliable = 1;
+}
+
+/* Open a connection to a remote debugger.
+   NAME is the filename used for communication.  */
+
+void
+remote_open (char *name)
+{
+  char *port_str;
+
+  port_str = strchr (name, ':');
+#ifdef USE_WIN32API
+  if (port_str == NULL)
+    error ("Only <host>:<port> is supported on this platform.");
+#endif
+
+  if (strcmp (name, STDIO_CONNECTION_NAME) == 0)
+    {
+      fprintf (stderr, "Remote debugging using stdio\n");
+
+      /* Use stdin as the handle of the connection.
+        We only select on reads, for example.  */
+      remote_desc = fileno (stdin);
+
+      enable_async_notification (remote_desc);
+
+      /* Register the event loop handler.  */
+      add_file_handler (remote_desc, handle_serial_event, NULL);
+    }
+#ifndef USE_WIN32API
+  else if (port_str == NULL)
+    {
       struct stat statbuf;
 
       if (stat (name, &statbuf) == 0
@@ -179,146 +369,53 @@ remote_open (char *name)
 #endif
 
       fprintf (stderr, "Remote debugging using %s\n", name);
-#endif /* USE_WIN32API */
+
+      enable_async_notification (remote_desc);
+
+      /* Register the event loop handler.  */
+      add_file_handler (remote_desc, handle_serial_event, NULL);
     }
+#endif /* USE_WIN32API */
   else
     {
-#ifdef USE_WIN32API
-      static int winsock_initialized;
-#endif
-      char *port_str;
       int port;
+      socklen_t len;
       struct sockaddr_in sockaddr;
-      socklen_t tmp;
-      int tmp_desc;
-
-      port_str = strchr (name, ':');
-
-      port = atoi (port_str + 1);
-
-#ifdef USE_WIN32API
-      if (!winsock_initialized)
-       {
-         WSADATA wsad;
-
-         WSAStartup (MAKEWORD (1, 0), &wsad);
-         winsock_initialized = 1;
-       }
-#endif
 
-      tmp_desc = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
-      if (tmp_desc < 0)
-       perror_with_name ("Can't open socket");
-
-      /* Allow rapid reuse of this port. */
-      tmp = 1;
-      setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp,
-                 sizeof (tmp));
-
-      sockaddr.sin_family = PF_INET;
-      sockaddr.sin_port = htons (port);
-      sockaddr.sin_addr.s_addr = INADDR_ANY;
-
-      if (bind (tmp_desc, (struct sockaddr *) &sockaddr, sizeof (sockaddr))
-         || listen (tmp_desc, 1))
-       perror_with_name ("Can't bind address");
-
-      /* If port is zero, a random port will be selected, and the
-        fprintf below needs to know what port was selected.  */
-      if (port == 0)
-       {
-         socklen_t len = sizeof (sockaddr);
-         if (getsockname (tmp_desc, (struct sockaddr *) &sockaddr, &len) < 0
-             || len < sizeof (sockaddr))
-           perror_with_name ("Can't determine port");
-         port = ntohs (sockaddr.sin_port);
-       }
+      len = sizeof (sockaddr);
+      if (getsockname (listen_desc,
+                      (struct sockaddr *) &sockaddr, &len) < 0
+         || len < sizeof (sockaddr))
+       perror_with_name ("Can't determine port");
+      port = ntohs (sockaddr.sin_port);
 
       fprintf (stderr, "Listening on port %d\n", port);
       fflush (stderr);
 
-      tmp = sizeof (sockaddr);
-      remote_desc = accept (tmp_desc, (struct sockaddr *) &sockaddr, &tmp);
-      if (remote_desc == -1)
-       perror_with_name ("Accept failed");
-
-      /* Enable TCP keep alive process. */
-      tmp = 1;
-      setsockopt (remote_desc, SOL_SOCKET, SO_KEEPALIVE,
-                 (char *) &tmp, sizeof (tmp));
-
-      /* Tell TCP not to delay small packets.  This greatly speeds up
-         interactive response. */
-      tmp = 1;
-      setsockopt (remote_desc, IPPROTO_TCP, TCP_NODELAY,
-                 (char *) &tmp, sizeof (tmp));
-
-
-#ifndef USE_WIN32API
-      close (tmp_desc);                /* No longer need this */
-
-      signal (SIGPIPE, SIG_IGN);       /* If we don't do this, then gdbserver simply
-                                          exits when the remote side dies.  */
-#else
-      closesocket (tmp_desc);  /* No longer need this */
-#endif
-
-      /* Convert IP address to string.  */
-      fprintf (stderr, "Remote debugging from host %s\n", 
-         inet_ntoa (sockaddr.sin_addr));
+      /* Register the event loop handler.  */
+      add_file_handler (listen_desc, handle_accept_event, NULL);
     }
-
-#if defined(F_SETFL) && defined (FASYNC)
-  save_fcntl_flags = fcntl (remote_desc, F_GETFL, 0);
-  fcntl (remote_desc, F_SETFL, save_fcntl_flags | FASYNC);
-#if defined (F_SETOWN)
-  fcntl (remote_desc, F_SETOWN, getpid ());
-#endif
-#endif
 }
 
 void
 remote_close (void)
 {
+  delete_file_handler (remote_desc);
+
 #ifdef USE_WIN32API
   closesocket (remote_desc);
 #else
-  close (remote_desc);
+  if (! remote_connection_is_stdio ())
+    close (remote_desc);
 #endif
-}
-
-/* Convert hex digit A to a number.  */
+  remote_desc = INVALID_DESCRIPTOR;
 
-static int
-fromhex (int a)
-{
-  if (a >= '0' && a <= '9')
-    return a - '0';
-  else if (a >= 'a' && a <= 'f')
-    return a - 'a' + 10;
-  else
-    error ("Reply contains invalid hex digit");
-  return 0;
+  reset_readchar ();
 }
 
-int
-unhexify (char *bin, const char *hex, int count)
-{
-  int i;
+#endif
 
-  for (i = 0; i < count; i++)
-    {
-      if (hex[0] == 0 || hex[1] == 0)
-        {
-          /* Hex string is short, or of uneven length.
-             Return the count that has been converted so far. */
-          return i;
-        }
-      *bin++ = fromhex (hex[0]) * 16 + fromhex (hex[1]);
-      hex += 2;
-    }
-  return i;
-}
+#ifndef IN_PROCESS_AGENT
 
 void
 decode_address (CORE_ADDR *addrp, const char *start, int len)
@@ -353,115 +450,9 @@ decode_address_to_semicolon (CORE_ADDR *addrp, const char *start)
   return end;
 }
 
-/* Convert number NIB to a hex digit.  */
-
-static int
-tohex (int nib)
-{
-  if (nib < 10)
-    return '0' + nib;
-  else
-    return 'a' + nib - 10;
-}
-
-int
-hexify (char *hex, const char *bin, int count)
-{
-  int i;
-
-  /* May use a length, or a nul-terminated string as input. */
-  if (count == 0)
-    count = strlen (bin);
-
-  for (i = 0; i < count; i++)
-    {
-      *hex++ = tohex ((*bin >> 4) & 0xf);
-      *hex++ = tohex (*bin++ & 0xf);
-    }
-  *hex = 0;
-  return i;
-}
-
-/* Convert BUFFER, binary data at least LEN bytes long, into escaped
-   binary data in OUT_BUF.  Set *OUT_LEN to the length of the data
-   encoded in OUT_BUF, and return the number of bytes in OUT_BUF
-   (which may be more than *OUT_LEN due to escape characters).  The
-   total number of bytes in the output buffer will be at most
-   OUT_MAXLEN.  */
-
-int
-remote_escape_output (const gdb_byte *buffer, int len,
-                     gdb_byte *out_buf, int *out_len,
-                     int out_maxlen)
-{
-  int input_index, output_index;
-
-  output_index = 0;
-  for (input_index = 0; input_index < len; input_index++)
-    {
-      gdb_byte b = buffer[input_index];
-
-      if (b == '$' || b == '#' || b == '}' || b == '*')
-       {
-         /* These must be escaped.  */
-         if (output_index + 2 > out_maxlen)
-           break;
-         out_buf[output_index++] = '}';
-         out_buf[output_index++] = b ^ 0x20;
-       }
-      else
-       {
-         if (output_index + 1 > out_maxlen)
-           break;
-         out_buf[output_index++] = b;
-       }
-    }
-
-  *out_len = input_index;
-  return output_index;
-}
-
-/* Convert BUFFER, escaped data LEN bytes long, into binary data
-   in OUT_BUF.  Return the number of bytes written to OUT_BUF.
-   Raise an error if the total number of bytes exceeds OUT_MAXLEN.
-
-   This function reverses remote_escape_output.  It allows more
-   escaped characters than that function does, in particular because
-   '*' must be escaped to avoid the run-length encoding processing
-   in reading packets.  */
-
-static int
-remote_unescape_input (const gdb_byte *buffer, int len,
-                      gdb_byte *out_buf, int out_maxlen)
-{
-  int input_index, output_index;
-  int escaped;
-
-  output_index = 0;
-  escaped = 0;
-  for (input_index = 0; input_index < len; input_index++)
-    {
-      gdb_byte b = buffer[input_index];
-
-      if (output_index + 1 > out_maxlen)
-       error ("Received too much data from the target.");
-
-      if (escaped)
-       {
-         out_buf[output_index++] = b ^ 0x20;
-         escaped = 0;
-       }
-      else if (b == '}')
-       escaped = 1;
-      else
-       out_buf[output_index++] = b;
-    }
-
-  if (escaped)
-    error ("Unmatched escape character in target response.");
+#endif
 
-  return output_index;
-}
+#ifndef IN_PROCESS_AGENT
 
 /* Look for a sequence of characters which can be run-length encoded.
    If there are any, update *CSUM and *P.  Otherwise, output the
@@ -507,26 +498,140 @@ try_rle (char *buf, int remaining, unsigned char *csum, char **p)
   return n + 1;
 }
 
+#endif
+
+#ifndef IN_PROCESS_AGENT
+
+/* Write a PTID to BUF.  Returns BUF+CHARACTERS_WRITTEN.  */
+
+char *
+write_ptid (char *buf, ptid_t ptid)
+{
+  int pid, tid;
+
+  if (multi_process)
+    {
+      pid = ptid_get_pid (ptid);
+      if (pid < 0)
+       buf += sprintf (buf, "p-%x.", -pid);
+      else
+       buf += sprintf (buf, "p%x.", pid);
+    }
+  tid = ptid_get_lwp (ptid);
+  if (tid < 0)
+    buf += sprintf (buf, "-%x", -tid);
+  else
+    buf += sprintf (buf, "%x", tid);
+
+  return buf;
+}
+
+static ULONGEST
+hex_or_minus_one (char *buf, char **obuf)
+{
+  ULONGEST ret;
+
+  if (startswith (buf, "-1"))
+    {
+      ret = (ULONGEST) -1;
+      buf += 2;
+    }
+  else
+    buf = unpack_varlen_hex (buf, &ret);
+
+  if (obuf)
+    *obuf = buf;
+
+  return ret;
+}
+
+/* Extract a PTID from BUF.  If non-null, OBUF is set to the to one
+   passed the last parsed char.  Returns null_ptid on error.  */
+ptid_t
+read_ptid (char *buf, char **obuf)
+{
+  char *p = buf;
+  char *pp;
+  ULONGEST pid = 0, tid = 0;
+
+  if (*p == 'p')
+    {
+      /* Multi-process ptid.  */
+      pp = unpack_varlen_hex (p + 1, &pid);
+      if (*pp != '.')
+       error ("invalid remote ptid: %s\n", p);
+
+      p = pp + 1;
+
+      tid = hex_or_minus_one (p, &pp);
+
+      if (obuf)
+       *obuf = pp;
+      return ptid_build (pid, tid, 0);
+    }
+
+  /* No multi-process.  Just a tid.  */
+  tid = hex_or_minus_one (p, &pp);
+
+  /* Since GDB is not sending a process id (multi-process extensions
+     are off), then there's only one process.  Default to the first in
+     the list.  */
+  pid = pid_of (get_first_process ());
+
+  if (obuf)
+    *obuf = pp;
+  return ptid_build (pid, tid, 0);
+}
+
+/* Write COUNT bytes in BUF to the client.
+   The result is the number of bytes written or -1 if error.
+   This may return less than COUNT.  */
+
+static int
+write_prim (const void *buf, int count)
+{
+  if (remote_connection_is_stdio ())
+    return write (fileno (stdout), buf, count);
+  else
+    return write (remote_desc, buf, count);
+}
+
+/* Read COUNT bytes from the client and store in BUF.
+   The result is the number of bytes read or -1 if error.
+   This may return less than COUNT.  */
+
+static int
+read_prim (void *buf, int count)
+{
+  if (remote_connection_is_stdio ())
+    return read (fileno (stdin), buf, count);
+  else
+    return read (remote_desc, buf, count);
+}
+
 /* Send a packet to the remote machine, with error checking.
    The data of the packet is in BUF, and the length of the
    packet is in CNT.  Returns >= 0 on success, -1 otherwise.  */
 
-int
-putpkt_binary (char *buf, int cnt)
+static int
+putpkt_binary_1 (char *buf, int cnt, int is_notif)
 {
   int i;
   unsigned char csum = 0;
   char *buf2;
-  char buf3[1];
   char *p;
+  int cc;
 
-  buf2 = malloc (PBUFSIZ);
+  buf2 = (char *) xmalloc (strlen ("$") + cnt + strlen ("#nn") + 1);
 
   /* Copy the packet into buffer BUF2, encapsulating it
      and giving it a checksum.  */
 
   p = buf2;
-  *p++ = '$';
+  if (is_notif)
+    *p++ = '%';
+  else
+    *p++ = '$';
 
   for (i = 0; i < cnt;)
     i += try_rle (buf + i, cnt - i, &csum, &p);
@@ -541,48 +646,63 @@ putpkt_binary (char *buf, int cnt)
 
   do
     {
-      int cc;
-
-      if (write (remote_desc, buf2, p - buf2) != p - buf2)
+      if (write_prim (buf2, p - buf2) != p - buf2)
        {
          perror ("putpkt(write)");
          free (buf2);
          return -1;
        }
 
-      if (remote_debug)
+      if (noack_mode || is_notif)
        {
-         fprintf (stderr, "putpkt (\"%s\"); [looking for ack]\n", buf2);
-         fflush (stderr);
+         /* Don't expect an ack then.  */
+         if (remote_debug)
+           {
+             if (is_notif)
+               fprintf (stderr, "putpkt (\"%s\"); [notif]\n", buf2);
+             else
+               fprintf (stderr, "putpkt (\"%s\"); [noack mode]\n", buf2);
+             fflush (stderr);
+           }
+         break;
        }
-      cc = read (remote_desc, buf3, 1);
+
       if (remote_debug)
        {
-         fprintf (stderr, "[received '%c' (0x%x)]\n", buf3[0], buf3[0]);
+         fprintf (stderr, "putpkt (\"%s\"); [looking for ack]\n", buf2);
          fflush (stderr);
        }
 
-      if (cc <= 0)
-       {
-         if (cc == 0)
-           fprintf (stderr, "putpkt(read): Got EOF\n");
-         else
-           perror ("putpkt(read)");
+      cc = readchar ();
 
+      if (cc < 0)
+       {
          free (buf2);
          return -1;
        }
 
+      if (remote_debug)
+       {
+         fprintf (stderr, "[received '%c' (0x%x)]\n", cc, cc);
+         fflush (stderr);
+       }
+
       /* Check for an input interrupt while we're here.  */
-      if (buf3[0] == '\003')
+      if (cc == '\003' && current_thread != NULL)
        (*the_target->request_interrupt) ();
     }
-  while (buf3[0] != '+');
+  while (cc != '+');
 
   free (buf2);
   return 1;                    /* Success! */
 }
 
+int
+putpkt_binary (char *buf, int cnt)
+{
+  return putpkt_binary_1 (buf, cnt, 0);
+}
+
 /* Send a packet to the remote machine, with error checking.  The data
    of the packet is in BUF, and the packet should be a NUL-terminated
    string.  Returns >= 0 on success, -1 otherwise.  */
@@ -593,9 +713,16 @@ putpkt (char *buf)
   return putpkt_binary (buf, strlen (buf));
 }
 
+int
+putpkt_notif (char *buf)
+{
+  return putpkt_binary_1 (buf, strlen (buf), 1);
+}
+
 /* Come here when we get an input interrupt from the remote side.  This
    interrupt should only be active while we are waiting for the child to do
-   something.  About the only thing that should come through is a ^C, which
+   something.  Thus this assumes readchar:bufcnt is 0.
+   About the only thing that should come through is a ^C, which
    will cause us to request child interruption.  */
 
 static void
@@ -614,12 +741,20 @@ input_interrupt (int unused)
       int cc;
       char c = 0;
 
-      cc = read (remote_desc, &c, 1);
+      cc = read_prim (&c, 1);
 
-      if (cc != 1 || c != '\003')
+      if (cc == 0)
        {
-         fprintf (stderr, "input_interrupt, count = %d c = %d ('%c')\n",
-                  cc, c, c);
+         fprintf (stderr, "client connection closed\n");
+         return;
+       }
+      else if (cc != 1 || c != '\003')
+       {
+         fprintf (stderr, "input_interrupt, count = %d c = %d ", cc, c);
+         if (isprint (c))
+           fprintf (stderr, "('%c')\n", c);
+         else
+           fprintf (stderr, "('\\x%02x')\n", c & 0xff);
          return;
        }
 
@@ -656,6 +791,28 @@ unblock_async_io (void)
 #endif
 }
 
+#ifdef __QNX__
+static void
+nto_comctrl (int enable)
+{
+  struct sigevent event;
+
+  if (enable)
+    {
+      event.sigev_notify = SIGEV_SIGNAL_THREAD;
+      event.sigev_signo = SIGIO;
+      event.sigev_code = 0;
+      event.sigev_value.sival_ptr = NULL;
+      event.sigev_priority = -1;
+      ionotify (remote_desc, _NOTIFY_ACTION_POLLARM, _NOTIFY_COND_INPUT,
+               &event);
+    }
+  else
+    ionotify (remote_desc, _NOTIFY_ACTION_POLL, _NOTIFY_COND_INPUT, NULL);
+}
+#endif /* __QNX__ */
+
+
 /* Current state of asynchronous I/O.  */
 static int async_io_enabled;
 
@@ -670,6 +827,9 @@ enable_async_io (void)
   signal (SIGIO, input_interrupt);
 #endif
   async_io_enabled = 1;
+#ifdef __QNX__
+  nto_comctrl (1);
+#endif /* __QNX__ */
 }
 
 /* Disable asynchronous I/O.  */
@@ -683,6 +843,10 @@ disable_async_io (void)
   signal (SIGIO, SIG_IGN);
 #endif
   async_io_enabled = 0;
+#ifdef __QNX__
+  nto_comctrl (0);
+#endif /* __QNX__ */
+
 }
 
 void
@@ -696,33 +860,86 @@ initialize_async_io (void)
   unblock_async_io ();
 }
 
+/* Internal buffer used by readchar.
+   These are global to readchar because reschedule_remote needs to be
+   able to tell whether the buffer is empty.  */
+
+static unsigned char readchar_buf[BUFSIZ];
+static int readchar_bufcnt = 0;
+static unsigned char *readchar_bufp;
+
 /* Returns next char from remote GDB.  -1 if error.  */
 
 static int
 readchar (void)
 {
-  static unsigned char buf[BUFSIZ];
-  static int bufcnt = 0;
-  static unsigned char *bufp;
+  int ch;
 
-  if (bufcnt-- > 0)
-    return *bufp++;
+  if (readchar_bufcnt == 0)
+    {
+      readchar_bufcnt = read_prim (readchar_buf, sizeof (readchar_buf));
 
-  bufcnt = read (remote_desc, buf, sizeof (buf));
+      if (readchar_bufcnt <= 0)
+       {
+         if (readchar_bufcnt == 0)
+           {
+             if (remote_debug)
+               fprintf (stderr, "readchar: Got EOF\n");
+           }
+         else
+           perror ("readchar");
 
-  if (bufcnt <= 0)
-    {
-      if (bufcnt == 0)
-       fprintf (stderr, "readchar: Got EOF\n");
-      else
-       perror ("readchar");
+         return -1;
+       }
 
-      return -1;
+      readchar_bufp = readchar_buf;
     }
 
-  bufp = buf;
-  bufcnt--;
-  return *bufp++;
+  readchar_bufcnt--;
+  ch = *readchar_bufp++;
+  reschedule ();
+  return ch;
+}
+
+/* Reset the readchar state machine.  */
+
+static void
+reset_readchar (void)
+{
+  readchar_bufcnt = 0;
+  if (readchar_callback != NOT_SCHEDULED)
+    {
+      delete_callback_event (readchar_callback);
+      readchar_callback = NOT_SCHEDULED;
+    }
+}
+
+/* Process remaining data in readchar_buf.  */
+
+static int
+process_remaining (void *context)
+{
+  int res;
+
+  /* This is a one-shot event.  */
+  readchar_callback = NOT_SCHEDULED;
+
+  if (readchar_bufcnt > 0)
+    res = handle_serial_event (0, NULL);
+  else
+    res = 0;
+
+  return res;
+}
+
+/* If there is still data in the buffer, queue another event to process it,
+   we can't sleep in select yet.  */
+
+static void
+reschedule (void)
+{
+  if (readchar_bufcnt > 0 && readchar_callback == NOT_SCHEDULED)
+    readchar_callback = append_callback_event (process_remaining, NULL);
 }
 
 /* Read a packet from the remote machine, with error checking,
@@ -742,6 +959,15 @@ getpkt (char *buf)
       while (1)
        {
          c = readchar ();
+
+         /* The '\003' may appear before or after each packet, so
+            check for an input interrupt.  */
+         if (c == '\003')
+           {
+             (*the_target->request_interrupt) ();
+             continue;
+           }
+
          if (c == '$')
            break;
          if (remote_debug)
@@ -773,23 +999,46 @@ getpkt (char *buf)
       if (csum == (c1 << 4) + c2)
        break;
 
+      if (noack_mode)
+       {
+         fprintf (stderr,
+                  "Bad checksum, sentsum=0x%x, csum=0x%x, "
+                  "buf=%s [no-ack-mode, Bad medium?]\n",
+                  (c1 << 4) + c2, csum, buf);
+         /* Not much we can do, GDB wasn't expecting an ack/nac.  */
+         break;
+       }
+
       fprintf (stderr, "Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n",
               (c1 << 4) + c2, csum, buf);
-      write (remote_desc, "-", 1);
+      if (write_prim ("-", 1) != 1)
+       return -1;
     }
 
-  if (remote_debug)
+  if (!noack_mode)
     {
-      fprintf (stderr, "getpkt (\"%s\");  [sending ack] \n", buf);
-      fflush (stderr);
-    }
+      if (remote_debug)
+       {
+         fprintf (stderr, "getpkt (\"%s\");  [sending ack] \n", buf);
+         fflush (stderr);
+       }
 
-  write (remote_desc, "+", 1);
+      if (write_prim ("+", 1) != 1)
+       return -1;
 
-  if (remote_debug)
+      if (remote_debug)
+       {
+         fprintf (stderr, "[sent ack]\n");
+         fflush (stderr);
+       }
+    }
+  else
     {
-      fprintf (stderr, "[sent ack]\n");
-      fflush (stderr);
+      if (remote_debug)
+       {
+         fprintf (stderr, "getpkt (\"%s\");  [no ack sent] \n", buf);
+         fflush (stderr);
+       }
     }
 
   return bp - buf;
@@ -813,37 +1062,12 @@ write_enn (char *buf)
   buf[3] = '\0';
 }
 
-void
-convert_int_to_ascii (unsigned char *from, char *to, int n)
-{
-  int nib;
-  int ch;
-  while (n--)
-    {
-      ch = *from++;
-      nib = ((ch & 0xf0) >> 4) & 0x0f;
-      *to++ = tohex (nib);
-      nib = ch & 0x0f;
-      *to++ = tohex (nib);
-    }
-  *to++ = 0;
-}
-
+#endif
 
-void
-convert_ascii_to_int (char *from, unsigned char *to, int n)
-{
-  int nib1, nib2;
-  while (n--)
-    {
-      nib1 = fromhex (*from++);
-      nib2 = fromhex (*from++);
-      *to++ = (((nib1 & 0x0f) << 4) & 0xf0) | (nib2 & 0x0f);
-    }
-}
+#ifndef IN_PROCESS_AGENT
 
 static char *
-outreg (int regno, char *buf)
+outreg (struct regcache *regcache, int regno, char *buf)
 {
   if ((regno >> 12) != 0)
     *buf++ = tohex ((regno >> 12) & 0xf);
@@ -852,8 +1076,8 @@ outreg (int regno, char *buf)
   *buf++ = tohex ((regno >> 4) & 0xf);
   *buf++ = tohex (regno & 0xf);
   *buf++ = ':';
-  collect_register_as_string (regno, buf);
-  buf += 2 * register_size (regno);
+  collect_register_as_string (regcache, regno, buf);
+  buf += 2 * register_size (regcache->tdesc, regno);
   *buf++ = ';';
 
   return buf;
@@ -893,88 +1117,197 @@ dead_thread_notify (int id)
 }
 
 void
-prepare_resume_reply (char *buf, char status, unsigned char sig)
+prepare_resume_reply (char *buf, ptid_t ptid,
+                     struct target_waitstatus *status)
 {
-  int nib;
-
-  *buf++ = status;
-
-  nib = ((sig & 0xf0) >> 4);
-  *buf++ = tohex (nib);
-  nib = sig & 0x0f;
-  *buf++ = tohex (nib);
+  if (debug_threads)
+    debug_printf ("Writing resume reply for %s:%d\n",
+                 target_pid_to_str (ptid), status->kind);
 
-  if (status == 'T')
+  switch (status->kind)
     {
-      const char **regp = gdbserver_expedite_regs;
-
-      if (the_target->stopped_by_watchpoint != NULL
-         && (*the_target->stopped_by_watchpoint) ())
-       {
-         CORE_ADDR addr;
-         int i;
-
-         strncpy (buf, "watch:", 6);
-         buf += 6;
-
-         addr = (*the_target->stopped_data_address) ();
-
-         /* Convert each byte of the address into two hexadecimal chars.
-            Note that we take sizeof (void *) instead of sizeof (addr);
-            this is to avoid sending a 64-bit address to a 32-bit GDB.  */
-         for (i = sizeof (void *) * 2; i > 0; i--)
-           {
+    case TARGET_WAITKIND_STOPPED:
+    case TARGET_WAITKIND_FORKED:
+    case TARGET_WAITKIND_VFORKED:
+    case TARGET_WAITKIND_VFORK_DONE:
+    case TARGET_WAITKIND_EXECD:
+    case TARGET_WAITKIND_THREAD_CREATED:
+      {
+       struct thread_info *saved_thread;
+       const char **regp;
+       struct regcache *regcache;
+
+       if ((status->kind == TARGET_WAITKIND_FORKED && report_fork_events)
+           || (status->kind == TARGET_WAITKIND_VFORKED && report_vfork_events))
+         {
+           enum gdb_signal signal = GDB_SIGNAL_TRAP;
+           const char *event = (status->kind == TARGET_WAITKIND_FORKED
+                                ? "fork" : "vfork");
+
+           sprintf (buf, "T%02x%s:", signal, event);
+           buf += strlen (buf);
+           buf = write_ptid (buf, status->value.related_pid);
+           strcat (buf, ";");
+         }
+       else if (status->kind == TARGET_WAITKIND_VFORK_DONE && report_vfork_events)
+         {
+           enum gdb_signal signal = GDB_SIGNAL_TRAP;
+
+           sprintf (buf, "T%02xvforkdone:;", signal);
+         }
+       else if (status->kind == TARGET_WAITKIND_EXECD && report_exec_events)
+         {
+           enum gdb_signal signal = GDB_SIGNAL_TRAP;
+           const char *event = "exec";
+           char hexified_pathname[PATH_MAX * 2];
+
+           sprintf (buf, "T%02x%s:", signal, event);
+           buf += strlen (buf);
+
+           /* Encode pathname to hexified format.  */
+           bin2hex ((const gdb_byte *) status->value.execd_pathname,
+                    hexified_pathname,
+                    strlen (status->value.execd_pathname));
+
+           sprintf (buf, "%s;", hexified_pathname);
+           xfree (status->value.execd_pathname);
+           status->value.execd_pathname = NULL;
+           buf += strlen (buf);
+         }
+       else if (status->kind == TARGET_WAITKIND_THREAD_CREATED
+                && report_thread_events)
+         {
+           enum gdb_signal signal = GDB_SIGNAL_TRAP;
+
+           sprintf (buf, "T%02xcreate:;", signal);
+         }
+       else
+         sprintf (buf, "T%02x", status->value.sig);
+
+       buf += strlen (buf);
+
+       saved_thread = current_thread;
+
+       current_thread = find_thread_ptid (ptid);
+
+       regp = current_target_desc ()->expedite_regs;
+
+       regcache = get_thread_regcache (current_thread, 1);
+
+       if (the_target->stopped_by_watchpoint != NULL
+           && (*the_target->stopped_by_watchpoint) ())
+         {
+           CORE_ADDR addr;
+           int i;
+
+           strncpy (buf, "watch:", 6);
+           buf += 6;
+
+           addr = (*the_target->stopped_data_address) ();
+
+           /* Convert each byte of the address into two hexadecimal
+              chars.  Note that we take sizeof (void *) instead of
+              sizeof (addr); this is to avoid sending a 64-bit
+              address to a 32-bit GDB.  */
+           for (i = sizeof (void *) * 2; i > 0; i--)
              *buf++ = tohex ((addr >> (i - 1) * 4) & 0xf);
-           }
-         *buf++ = ';';
-       }
-
-      while (*regp)
-       {
-         buf = outreg (find_regno (*regp), buf);
-         regp ++;
-       }
-
-      /* Formerly, if the debugger had not used any thread features we would not
-        burden it with a thread status response.  This was for the benefit of
-        GDB 4.13 and older.  However, in recent GDB versions the check
-        (``if (cont_thread != 0)'') does not have the desired effect because of
-        sillyness in the way that the remote protocol handles specifying a thread.
-        Since thread support relies on qSymbol support anyway, assume GDB can handle
-        threads.  */
-
-      if (using_threads)
-       {
-         unsigned int gdb_id_from_wait;
-
-         /* FIXME right place to set this? */
-         thread_from_wait = ((struct inferior_list_entry *)current_inferior)->id;
-         gdb_id_from_wait = thread_to_gdb_id (current_inferior);
-
-         if (debug_threads)
-           fprintf (stderr, "Writing resume reply for %ld\n\n", thread_from_wait);
-         /* This if (1) ought to be unnecessary.  But remote_wait in GDB
-            will claim this event belongs to inferior_ptid if we do not
-            specify a thread, and there's no way for gdbserver to know
-            what inferior_ptid is.  */
-         if (1 || old_thread_from_wait != thread_from_wait)
-           {
-             general_thread = thread_from_wait;
-             sprintf (buf, "thread:%x;", gdb_id_from_wait);
-             buf += strlen (buf);
-             old_thread_from_wait = thread_from_wait;
-           }
-       }
-
-      if (dlls_changed)
-       {
-         strcpy (buf, "library:;");
-         buf += strlen (buf);
-         dlls_changed = 0;
-       }
+           *buf++ = ';';
+         }
+       else if (swbreak_feature && target_stopped_by_sw_breakpoint ())
+         {
+           sprintf (buf, "swbreak:;");
+           buf += strlen (buf);
+         }
+       else if (hwbreak_feature && target_stopped_by_hw_breakpoint ())
+         {
+           sprintf (buf, "hwbreak:;");
+           buf += strlen (buf);
+         }
+
+       while (*regp)
+         {
+           buf = outreg (regcache, find_regno (regcache->tdesc, *regp), buf);
+           regp ++;
+         }
+       *buf = '\0';
+
+       /* Formerly, if the debugger had not used any thread features
+          we would not burden it with a thread status response.  This
+          was for the benefit of GDB 4.13 and older.  However, in
+          recent GDB versions the check (``if (cont_thread != 0)'')
+          does not have the desired effect because of sillyness in
+          the way that the remote protocol handles specifying a
+          thread.  Since thread support relies on qSymbol support
+          anyway, assume GDB can handle threads.  */
+
+       if (using_threads && !disable_packet_Tthread)
+         {
+           /* This if (1) ought to be unnecessary.  But remote_wait
+              in GDB will claim this event belongs to inferior_ptid
+              if we do not specify a thread, and there's no way for
+              gdbserver to know what inferior_ptid is.  */
+           if (1 || !ptid_equal (general_thread, ptid))
+             {
+               int core = -1;
+               /* In non-stop, don't change the general thread behind
+                  GDB's back.  */
+               if (!non_stop)
+                 general_thread = ptid;
+               sprintf (buf, "thread:");
+               buf += strlen (buf);
+               buf = write_ptid (buf, ptid);
+               strcat (buf, ";");
+               buf += strlen (buf);
+
+               core = target_core_of_thread (ptid);
+
+               if (core != -1)
+                 {
+                   sprintf (buf, "core:");
+                   buf += strlen (buf);
+                   sprintf (buf, "%x", core);
+                   strcat (buf, ";");
+                   buf += strlen (buf);
+                 }
+             }
+         }
+
+       if (dlls_changed)
+         {
+           strcpy (buf, "library:;");
+           buf += strlen (buf);
+           dlls_changed = 0;
+         }
+
+       current_thread = saved_thread;
+      }
+      break;
+    case TARGET_WAITKIND_EXITED:
+      if (multi_process)
+       sprintf (buf, "W%x;process:%x",
+                status->value.integer, ptid_get_pid (ptid));
+      else
+       sprintf (buf, "W%02x", status->value.integer);
+      break;
+    case TARGET_WAITKIND_SIGNALLED:
+      if (multi_process)
+       sprintf (buf, "X%x;process:%x",
+                status->value.sig, ptid_get_pid (ptid));
+      else
+       sprintf (buf, "X%02x", status->value.sig);
+      break;
+    case TARGET_WAITKIND_THREAD_EXITED:
+      sprintf (buf, "w%x;", status->value.integer);
+      buf += strlen (buf);
+      buf = write_ptid (buf, ptid);
+      break;
+    case TARGET_WAITKIND_NO_RESUMED:
+      sprintf (buf, "N");
+      break;
+    default:
+      error ("unhandled waitkind");
+      break;
     }
-  /* For W and X, we're done.  */
-  *buf++ = 0;
 }
 
 void
@@ -1001,7 +1334,7 @@ decode_m_packet (char *from, CORE_ADDR *mem_addr_ptr, unsigned int *len_ptr)
 
 void
 decode_M_packet (char *from, CORE_ADDR *mem_addr_ptr, unsigned int *len_ptr,
-                unsigned char *to)
+                unsigned char **to_p)
 {
   int i = 0;
   char ch;
@@ -1019,12 +1352,15 @@ decode_M_packet (char *from, CORE_ADDR *mem_addr_ptr, unsigned int *len_ptr,
       *len_ptr |= fromhex (ch) & 0x0f;
     }
 
-  convert_ascii_to_int (&from[i++], to, *len_ptr);
+  if (*to_p == NULL)
+    *to_p = (unsigned char *) xmalloc (*len_ptr);
+
+  hex2bin (&from[i++], *to_p, *len_ptr);
 }
 
 int
 decode_X_packet (char *from, int packet_len, CORE_ADDR *mem_addr_ptr,
-                unsigned int *len_ptr, unsigned char *to)
+                unsigned int *len_ptr, unsigned char **to_p)
 {
   int i = 0;
   char ch;
@@ -1042,27 +1378,24 @@ decode_X_packet (char *from, int packet_len, CORE_ADDR *mem_addr_ptr,
       *len_ptr |= fromhex (ch) & 0x0f;
     }
 
+  if (*to_p == NULL)
+    *to_p = (unsigned char *) xmalloc (*len_ptr);
+
   if (remote_unescape_input ((const gdb_byte *) &from[i], packet_len - i,
-                            to, *len_ptr) != *len_ptr)
+                            *to_p, *len_ptr) != *len_ptr)
     return -1;
 
   return 0;
 }
 
 /* Decode a qXfer write request.  */
+
 int
-decode_xfer_write (char *buf, int packet_len, char **annex, CORE_ADDR *offset,
+decode_xfer_write (char *buf, int packet_len, CORE_ADDR *offset,
                   unsigned int *len, unsigned char *data)
 {
   char ch;
-
-  /* Extract and NUL-terminate the annex.  */
-  *annex = buf;
-  while (*buf && *buf != ':')
-    buf++;
-  if (*buf == '\0')
-    return -1;
-  *buf++ = 0;
+  char *b = buf;
 
   /* Extract the offset.  */
   *offset = 0;
@@ -1073,41 +1406,86 @@ decode_xfer_write (char *buf, int packet_len, char **annex, CORE_ADDR *offset,
     }
 
   /* Get encoded data.  */
-  packet_len -= buf - *annex;
+  packet_len -= buf - b;
   *len = remote_unescape_input ((const gdb_byte *) buf, packet_len,
                                data, packet_len);
   return 0;
 }
 
-/* Ask GDB for the address of NAME, and return it in ADDRP if found.
+/* Decode the parameters of a qSearch:memory packet.  */
+
+int
+decode_search_memory_packet (const char *buf, int packet_len,
+                            CORE_ADDR *start_addrp,
+                            CORE_ADDR *search_space_lenp,
+                            gdb_byte *pattern, unsigned int *pattern_lenp)
+{
+  const char *p = buf;
+
+  p = decode_address_to_semicolon (start_addrp, p);
+  p = decode_address_to_semicolon (search_space_lenp, p);
+  packet_len -= p - buf;
+  *pattern_lenp = remote_unescape_input ((const gdb_byte *) p, packet_len,
+                                        pattern, packet_len);
+  return 0;
+}
+
+static void
+free_sym_cache (struct sym_cache *sym)
+{
+  if (sym != NULL)
+    {
+      free (sym->name);
+      free (sym);
+    }
+}
+
+void
+clear_symbol_cache (struct sym_cache **symcache_p)
+{
+  struct sym_cache *sym, *next;
+
+  /* Check the cache first.  */
+  for (sym = *symcache_p; sym; sym = next)
+    {
+      next = sym->next;
+      free_sym_cache (sym);
+    }
+
+  *symcache_p = NULL;
+}
+
+/* Get the address of NAME, and return it in ADDRP if found.  if
+   MAY_ASK_GDB is false, assume symbol cache misses are failures.
    Returns 1 if the symbol is found, 0 if it is not, -1 on error.  */
 
 int
-look_up_one_symbol (const char *name, CORE_ADDR *addrp)
+look_up_one_symbol (const char *name, CORE_ADDR *addrp, int may_ask_gdb)
 {
   char own_buf[266], *p, *q;
   int len;
   struct sym_cache *sym;
+  struct process_info *proc;
+
+  proc = current_process ();
 
   /* Check the cache first.  */
-  for (sym = symbol_cache; sym; sym = sym->next)
+  for (sym = proc->symbol_cache; sym; sym = sym->next)
     if (strcmp (name, sym->name) == 0)
       {
        *addrp = sym->addr;
        return 1;
       }
 
-  /* If we've passed the call to thread_db_look_up_symbols, then
-     anything not in the cache must not exist; we're not interested
-     in any libraries loaded after that point, only in symbols in
-     libpthread.so.  It might not be an appropriate time to look
-     up a symbol, e.g. while we're trying to fetch registers.  */
-  if (all_symbols_looked_up)
+  /* It might not be an appropriate time to look up a symbol,
+     e.g. while we're trying to fetch registers.  */
+  if (!may_ask_gdb)
     return 0;
 
   /* Send the request.  */
   strcpy (own_buf, "qSymbol:");
-  hexify (own_buf + strlen ("qSymbol:"), name, strlen (name));
+  bin2hex ((const gdb_byte *) name, own_buf + strlen ("qSymbol:"),
+         strlen (name));
   if (putpkt (own_buf) < 0)
     return -1;
 
@@ -1128,9 +1506,9 @@ look_up_one_symbol (const char *name, CORE_ADDR *addrp)
       unsigned int mem_len;
 
       decode_m_packet (&own_buf[1], &mem_addr, &mem_len);
-      mem_buf = malloc (mem_len);
+      mem_buf = (unsigned char *) xmalloc (mem_len);
       if (read_inferior_memory (mem_addr, mem_buf, mem_len) == 0)
-       convert_int_to_ascii (mem_buf, own_buf, mem_len);
+       bin2hex (mem_buf, own_buf, mem_len);
       else
        write_enn (own_buf);
       free (mem_buf);
@@ -1140,8 +1518,8 @@ look_up_one_symbol (const char *name, CORE_ADDR *addrp)
       if (len < 0)
        return -1;
     }
-  
-  if (strncmp (own_buf, "qSymbol:", strlen ("qSymbol:")) != 0)
+
+  if (!startswith (own_buf, "qSymbol:"))
     {
       warning ("Malformed response to qSymbol, ignoring: %s\n", own_buf);
       return -1;
@@ -1159,85 +1537,121 @@ look_up_one_symbol (const char *name, CORE_ADDR *addrp)
   decode_address (addrp, p, q - p);
 
   /* Save the symbol in our cache.  */
-  sym = malloc (sizeof (*sym));
-  sym->name = strdup (name);
+  sym = XNEW (struct sym_cache);
+  sym->name = xstrdup (name);
   sym->addr = *addrp;
-  sym->next = symbol_cache;
-  symbol_cache = sym;
+  sym->next = proc->symbol_cache;
+  proc->symbol_cache = sym;
 
   return 1;
 }
 
+/* Relocate an instruction to execute at a different address.  OLDLOC
+   is the address in the inferior memory where the instruction to
+   relocate is currently at.  On input, TO points to the destination
+   where we want the instruction to be copied (and possibly adjusted)
+   to.  On output, it points to one past the end of the resulting
+   instruction(s).  The effect of executing the instruction at TO
+   shall be the same as if executing it at OLDLOC.  For example, call
+   instructions that implicitly push the return address on the stack
+   should be adjusted to return to the instruction after OLDLOC;
+   relative branches, and other PC-relative instructions need the
+   offset adjusted; etc.  Returns 0 on success, -1 on failure.  */
+
+int
+relocate_instruction (CORE_ADDR *to, CORE_ADDR oldloc)
+{
+  char own_buf[266];
+  int len;
+  ULONGEST written = 0;
+
+  /* Send the request.  */
+  strcpy (own_buf, "qRelocInsn:");
+  sprintf (own_buf, "qRelocInsn:%s;%s", paddress (oldloc),
+          paddress (*to));
+  if (putpkt (own_buf) < 0)
+    return -1;
+
+  /* FIXME:  Eventually add buffer overflow checking (to getpkt?)  */
+  len = getpkt (own_buf);
+  if (len < 0)
+    return -1;
+
+  /* We ought to handle pretty much any packet at this point while we
+     wait for the qRelocInsn "response".  That requires re-entering
+     the main loop.  For now, this is an adequate approximation; allow
+     GDB to access memory.  */
+  while (own_buf[0] == 'm' || own_buf[0] == 'M' || own_buf[0] == 'X')
+    {
+      CORE_ADDR mem_addr;
+      unsigned char *mem_buf = NULL;
+      unsigned int mem_len;
+
+      if (own_buf[0] == 'm')
+       {
+         decode_m_packet (&own_buf[1], &mem_addr, &mem_len);
+         mem_buf = (unsigned char *) xmalloc (mem_len);
+         if (read_inferior_memory (mem_addr, mem_buf, mem_len) == 0)
+           bin2hex (mem_buf, own_buf, mem_len);
+         else
+           write_enn (own_buf);
+       }
+      else if (own_buf[0] == 'X')
+       {
+         if (decode_X_packet (&own_buf[1], len - 1, &mem_addr,
+                              &mem_len, &mem_buf) < 0
+             || write_inferior_memory (mem_addr, mem_buf, mem_len) != 0)
+           write_enn (own_buf);
+         else
+           write_ok (own_buf);
+       }
+      else
+       {
+         decode_M_packet (&own_buf[1], &mem_addr, &mem_len, &mem_buf);
+         if (write_inferior_memory (mem_addr, mem_buf, mem_len) == 0)
+           write_ok (own_buf);
+         else
+           write_enn (own_buf);
+       }
+      free (mem_buf);
+      if (putpkt (own_buf) < 0)
+       return -1;
+      len = getpkt (own_buf);
+      if (len < 0)
+       return -1;
+    }
+
+  if (own_buf[0] == 'E')
+    {
+      warning ("An error occurred while relocating an instruction: %s\n",
+              own_buf);
+      return -1;
+    }
+
+  if (!startswith (own_buf, "qRelocInsn:"))
+    {
+      warning ("Malformed response to qRelocInsn, ignoring: %s\n",
+              own_buf);
+      return -1;
+    }
+
+  unpack_varlen_hex (own_buf + strlen ("qRelocInsn:"), &written);
+
+  *to += written;
+  return 0;
+}
+
 void
 monitor_output (const char *msg)
 {
-  char *buf = malloc (strlen (msg) * 2 + 2);
+  int len = strlen (msg);
+  char *buf = (char *) xmalloc (len * 2 + 2);
 
   buf[0] = 'O';
-  hexify (buf + 1, msg, 0);
+  bin2hex ((const gdb_byte *) msg, buf + 1, len);
 
   putpkt (buf);
   free (buf);
 }
 
-/* Return a malloc allocated string with special characters from TEXT
-   replaced by entity references.  */
-
-char *
-xml_escape_text (const char *text)
-{
-  char *result;
-  int i, special;
-
-  /* Compute the length of the result.  */
-  for (i = 0, special = 0; text[i] != '\0'; i++)
-    switch (text[i])
-      {
-      case '\'':
-      case '\"':
-       special += 5;
-       break;
-      case '&':
-       special += 4;
-       break;
-      case '<':
-      case '>':
-       special += 3;
-       break;
-      default:
-       break;
-      }
-
-  /* Expand the result.  */
-  result = malloc (i + special + 1);
-  for (i = 0, special = 0; text[i] != '\0'; i++)
-    switch (text[i])
-      {
-      case '\'':
-       strcpy (result + i + special, "&apos;");
-       special += 5;
-       break;
-      case '\"':
-       strcpy (result + i + special, "&quot;");
-       special += 5;
-       break;
-      case '&':
-       strcpy (result + i + special, "&amp;");
-       special += 4;
-       break;
-      case '<':
-       strcpy (result + i + special, "&lt;");
-       special += 3;
-       break;
-      case '>':
-       strcpy (result + i + special, "&gt;");
-       special += 3;
-       break;
-      default:
-       result[i + special] = text[i];
-       break;
-      }
-  result[i + special] = '\0';
-
-  return result;
-}
+#endif