gdb/gdbserver/
[deliverable/binutils-gdb.git] / gdb / gdbserver / remote-utils.c
index 103bcc76eaae42eb6c97abf3060430ea8317dd39..3dfd1c9a00314fe617b92dac200f2685ffae48e1 100644 (file)
@@ -1,6 +1,6 @@
 /* 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, 2008, 2009
+   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
 
    This file is part of GDB.
 #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
@@ -76,6 +80,20 @@ typedef int socklen_t;
 # 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
 {
@@ -88,6 +106,7 @@ int remote_debug = 0;
 struct ui_file *gdb_stdlog;
 
 static int remote_desc = INVALID_DESCRIPTOR;
+static int listen_desc = INVALID_DESCRIPTOR;
 
 /* FIXME headerize? */
 extern int using_threads;
@@ -103,15 +122,88 @@ int transport_is_reliable = 0;
 # define write(fd, buf, len) send (fd, (char *) buf, len, 0)
 #endif
 
+int
+gdb_connected (void)
+{
+  return remote_desc != INVALID_DESCRIPTOR;
+}
+
+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)
+    fprintf (stderr, "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
+  close (listen_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 (listen_desc);   /* No longer need this */
+#endif
+
+  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;
+}
+
 /* Open a connection to a remote debugger.
    NAME is the filename used for communication.  */
 
 void
 remote_open (char *name)
 {
-#if defined(F_SETFL) && defined (FASYNC)
-  int save_fcntl_flags;
-#endif
   char *port_str;
 
   port_str = strchr (name, ':');
@@ -179,9 +271,14 @@ remote_open (char *name)
 #endif
 
       fprintf (stderr, "Remote debugging using %s\n", name);
-#endif /* USE_WIN32API */
 
       transport_is_reliable = 0;
+
+      enable_async_notification (remote_desc);
+
+      /* Register the event loop handler.  */
+      add_file_handler (remote_desc, handle_serial_event, NULL);
+#endif /* USE_WIN32API */
     }
   else
     {
@@ -191,7 +288,6 @@ remote_open (char *name)
       int port;
       struct sockaddr_in sockaddr;
       socklen_t tmp;
-      int tmp_desc;
       char *port_end;
 
       port = strtoul (port_str + 1, &port_end, 10);
@@ -208,21 +304,21 @@ remote_open (char *name)
        }
 #endif
 
-      tmp_desc = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
-      if (tmp_desc < 0)
+      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 (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp,
+      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 (tmp_desc, (struct sockaddr *) &sockaddr, sizeof (sockaddr))
-         || listen (tmp_desc, 1))
+      if (bind (listen_desc, (struct sockaddr *) &sockaddr, sizeof (sockaddr))
+         || listen (listen_desc, 1))
        perror_with_name ("Can't bind address");
 
       /* If port is zero, a random port will be selected, and the
@@ -230,7 +326,7 @@ remote_open (char *name)
       if (port == 0)
        {
          socklen_t len = sizeof (sockaddr);
-         if (getsockname (tmp_desc, (struct sockaddr *) &sockaddr, &len) < 0
+         if (getsockname (listen_desc, (struct sockaddr *) &sockaddr, &len) < 0
              || len < sizeof (sockaddr))
            perror_with_name ("Can't determine port");
          port = ntohs (sockaddr.sin_port);
@@ -239,49 +335,11 @@ remote_open (char *name)
       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);
 
       transport_is_reliable = 1;
     }
-
-#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
-
-  /* Register the event loop handler.  */
-  add_file_handler (remote_desc, handle_serial_event, NULL);
 }
 
 void
@@ -294,6 +352,9 @@ remote_close (void)
 #else
   close (remote_desc);
 #endif
+  remote_desc = INVALID_DESCRIPTOR;
+
+  reset_readchar ();
 }
 
 /* Convert hex digit A to a number.  */
@@ -646,8 +707,8 @@ 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 = xmalloc (PBUFSIZ);
 
@@ -673,8 +734,6 @@ putpkt_binary_1 (char *buf, int cnt, int is_notif)
 
   do
     {
-      int cc;
-
       if (write (remote_desc, buf2, p - buf2) != p - buf2)
        {
          perror ("putpkt(write)");
@@ -701,29 +760,26 @@ putpkt_binary_1 (char *buf, int cnt, int is_notif)
          fprintf (stderr, "putpkt (\"%s\"); [looking for ack]\n", buf2);
          fflush (stderr);
        }
-      cc = read (remote_desc, buf3, 1);
-      if (remote_debug)
-       {
-         fprintf (stderr, "[received '%c' (0x%x)]\n", buf3[0], buf3[0]);
-         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' && current_inferior != NULL)
+      if (cc == '\003' && current_inferior != NULL)
        (*the_target->request_interrupt) ();
     }
-  while (buf3[0] != '+');
+  while (cc != '+');
 
   free (buf2);
   return 1;                    /* Success! */
@@ -753,7 +809,8 @@ putpkt_notif (char *buf)
 
 /* 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
@@ -814,6 +871,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;
 
@@ -828,6 +907,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.  */
@@ -841,6 +923,10 @@ disable_async_io (void)
   signal (SIGIO, SIG_IGN);
 #endif
   async_io_enabled = 0;
+#ifdef __QNX__
+  nto_comctrl (0);
+#endif /* __QNX__ */
+
 }
 
 void
@@ -854,33 +940,83 @@ 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 (remote_desc, readchar_buf, sizeof (readchar_buf));
 
-  bufcnt = read (remote_desc, buf, sizeof (buf));
+      if (readchar_bufcnt <= 0)
+       {
+         if (readchar_bufcnt == 0)
+           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,
@@ -991,7 +1127,7 @@ write_enn (char *buf)
 }
 
 void
-convert_int_to_ascii (unsigned char *from, char *to, int n)
+convert_int_to_ascii (const unsigned char *from, char *to, int n)
 {
   int nib;
   int ch;
@@ -1008,7 +1144,7 @@ convert_int_to_ascii (unsigned char *from, char *to, int n)
 
 
 void
-convert_ascii_to_int (char *from, unsigned char *to, int n)
+convert_ascii_to_int (const char *from, unsigned char *to, int n)
 {
   int nib1, nib2;
   while (n--)
@@ -1020,7 +1156,7 @@ convert_ascii_to_int (char *from, unsigned char *to, int n)
 }
 
 static char *
-outreg (int regno, char *buf)
+outreg (struct regcache *regcache, int regno, char *buf)
 {
   if ((regno >> 12) != 0)
     *buf++ = tohex ((regno >> 12) & 0xf);
@@ -1029,7 +1165,7 @@ outreg (int regno, char *buf)
   *buf++ = tohex ((regno >> 4) & 0xf);
   *buf++ = tohex (regno & 0xf);
   *buf++ = ':';
-  collect_register_as_string (regno, buf);
+  collect_register_as_string (regcache, regno, buf);
   buf += 2 * register_size (regno);
   *buf++ = ';';
 
@@ -1083,6 +1219,7 @@ prepare_resume_reply (char *buf, ptid_t ptid,
       {
        struct thread_info *saved_inferior;
        const char **regp;
+       struct regcache *regcache;
 
        sprintf (buf, "T%02x", status->value.sig);
        buf += strlen (buf);
@@ -1091,7 +1228,9 @@ prepare_resume_reply (char *buf, ptid_t ptid,
 
        saved_inferior = current_inferior;
 
-       current_inferior = find_thread_pid (ptid);
+       current_inferior = find_thread_ptid (ptid);
+
+       regcache = get_thread_regcache (current_inferior, 1);
 
        if (the_target->stopped_by_watchpoint != NULL
            && (*the_target->stopped_by_watchpoint) ())
@@ -1115,9 +1254,10 @@ prepare_resume_reply (char *buf, ptid_t ptid,
 
        while (*regp)
          {
-           buf = outreg (find_regno (*regp), buf);
+           buf = outreg (regcache, find_regno (*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
@@ -1136,6 +1276,7 @@ prepare_resume_reply (char *buf, ptid_t ptid,
               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)
@@ -1145,6 +1286,17 @@ prepare_resume_reply (char *buf, ptid_t ptid,
                buf = write_ptid (buf, ptid);
                strcat (buf, ";");
                buf += strlen (buf);
+
+               if (the_target->core_of_thread)
+                 core = (*the_target->core_of_thread) (ptid);
+               if (core != -1)
+                 {
+                   sprintf (buf, "core:");
+                   buf += strlen (buf);
+                   sprintf (buf, "%x", core);
+                   strcat (buf, ";");
+                   buf += strlen (buf);
+                 }
              }
          }
 
@@ -1202,7 +1354,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;
@@ -1220,12 +1372,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 = xmalloc (*len_ptr);
+
+  convert_ascii_to_int (&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;
@@ -1243,8 +1398,11 @@ decode_X_packet (char *from, int packet_len, CORE_ADDR *mem_addr_ptr,
       *len_ptr |= fromhex (ch) & 0x0f;
     }
 
+  if (*to_p == NULL)
+    *to_p = 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;
@@ -1323,11 +1481,12 @@ clear_symbol_cache (struct sym_cache **symcache_p)
   *symcache_p = NULL;
 }
 
-/* Ask GDB for the address of NAME, and return it in ADDRP if found.
+/* 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;
@@ -1344,12 +1503,9 @@ look_up_one_symbol (const char *name, CORE_ADDR *addrp)
        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 (proc->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.  */
@@ -1415,6 +1571,101 @@ look_up_one_symbol (const char *name, CORE_ADDR *addrp)
   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 FROM.  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 = xmalloc (mem_len);
+         if (read_inferior_memory (mem_addr, mem_buf, mem_len) == 0)
+           convert_int_to_ascii (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 (strncmp (own_buf, "qRelocInsn:", strlen ("qRelocInsn:")) != 0)
+    {
+      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)
 {
@@ -1570,6 +1821,16 @@ buffer_xml_printf (struct buffer *buffer, const char *format, ...)
               prev = f + 1;
             }
             break;
+          case 'd':
+            {
+              int i = va_arg (ap, int);
+              char b[sizeof ("4294967295")];
+
+              buffer_grow (buffer, prev, f - prev - 1);
+              sprintf (b, "%d", i);
+              buffer_grow_str (buffer, b);
+              prev = f + 1;
+            }
           }
         percent = 0;
        }
This page took 0.032915 seconds and 4 git commands to generate.