* remote-utils.c (getpkt): Also generate remote-debug
[deliverable/binutils-gdb.git] / gdb / gdbserver / remote-utils.c
index 505e37c907d2f1847815de25f320cf967558c683..c87751664a2eb3e69a1952d8c5813c85aa5f2676 100644 (file)
@@ -1,12 +1,13 @@
 /* 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.
+   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   Free Software Foundation, Inc.
 
    This file is part of GDB.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
@@ -15,9 +16,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "server.h"
 #include "terminal.h"
@@ -100,6 +99,11 @@ static int remote_desc = INVALID_DESCRIPTOR;
 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)
@@ -182,21 +186,23 @@ remote_open (char *name)
 
       fprintf (stderr, "Remote debugging using %s\n", name);
 #endif /* USE_WIN32API */
+
+      transport_is_reliable = 0;
     }
   else
     {
 #ifdef USE_WIN32API
       static int winsock_initialized;
 #endif
-      char *port_str;
       int port;
       struct sockaddr_in sockaddr;
       socklen_t tmp;
       int tmp_desc;
+      char *port_end;
 
-      port_str = strchr (name, ':');
-
-      port = atoi (port_str + 1);
+      port = strtoul (port_str + 1, &port_end, 10);
+      if (port_str[1] == '\0' || *port_end != '\0')
+       fatal ("Bad port argument: %s", name);
 
 #ifdef USE_WIN32API
       if (!winsock_initialized)
@@ -246,7 +252,8 @@ remote_open (char *name)
 
       /* Enable TCP keep alive process. */
       tmp = 1;
-      setsockopt (tmp_desc, SOL_SOCKET, SO_KEEPALIVE, (char *) &tmp, sizeof (tmp));
+      setsockopt (remote_desc, SOL_SOCKET, SO_KEEPALIVE,
+                 (char *) &tmp, sizeof (tmp));
 
       /* Tell TCP not to delay small packets.  This greatly speeds up
          interactive response. */
@@ -267,6 +274,8 @@ remote_open (char *name)
       /* Convert IP address to string.  */
       fprintf (stderr, "Remote debugging from host %s\n", 
          inet_ntoa (sockaddr.sin_addr));
+
+      transport_is_reliable = 1;
     }
 
 #if defined(F_SETFL) && defined (FASYNC)
@@ -276,7 +285,6 @@ remote_open (char *name)
   fcntl (remote_desc, F_SETOWN, getpid ());
 #endif
 #endif
-  disable_async_io ();
 }
 
 void
@@ -522,7 +530,7 @@ putpkt_binary (char *buf, int cnt)
   char buf3[1];
   char *p;
 
-  buf2 = malloc (PBUFSIZ);
+  buf2 = xmalloc (PBUFSIZ);
 
   /* Copy the packet into buffer BUF2, encapsulating it
      and giving it a checksum.  */
@@ -548,9 +556,21 @@ putpkt_binary (char *buf, int cnt)
       if (write (remote_desc, buf2, p - buf2) != p - buf2)
        {
          perror ("putpkt(write)");
+         free (buf2);
          return -1;
        }
 
+      if (noack_mode)
+       {
+         /* Don't expect an ack then.  */
+         if (remote_debug)
+           {
+             fprintf (stderr, "putpkt (\"%s\"); [noack mode]\n", buf2);
+             fflush (stderr);
+           }
+         break;
+       }
+
       if (remote_debug)
        {
          fprintf (stderr, "putpkt (\"%s\"); [looking for ack]\n", buf2);
@@ -575,7 +595,7 @@ putpkt_binary (char *buf, int cnt)
        }
 
       /* Check for an input interrupt while we're here.  */
-      if (buf3[0] == '\003')
+      if (buf3[0] == '\003' && current_inferior != NULL)
        (*the_target->request_interrupt) ();
     }
   while (buf3[0] != '+');
@@ -617,7 +637,7 @@ input_interrupt (int unused)
 
       cc = read (remote_desc, &c, 1);
 
-      if (cc != 1 || c != '\003')
+      if (cc != 1 || c != '\003' || current_inferior == NULL)
        {
          fprintf (stderr, "input_interrupt, count = %d c = %d ('%c')\n",
                   cc, c, c);
@@ -645,22 +665,12 @@ check_remote_input_interrupt_request (void)
    accept Control-C from the client, and must be disabled when talking to
    the client.  */
 
-void
-block_async_io (void)
-{
-#ifndef USE_WIN32API
-  sigset_t sigio_set;
-  sigemptyset (&sigio_set);
-  sigaddset (&sigio_set, SIGIO);
-  sigprocmask (SIG_BLOCK, &sigio_set, NULL);
-#endif
-}
-
-void
+static void
 unblock_async_io (void)
 {
 #ifndef USE_WIN32API
   sigset_t sigio_set;
+
   sigemptyset (&sigio_set);
   sigaddset (&sigio_set, SIGIO);
   sigprocmask (SIG_UNBLOCK, &sigio_set, NULL);
@@ -696,6 +706,17 @@ disable_async_io (void)
   async_io_enabled = 0;
 }
 
+void
+initialize_async_io (void)
+{
+  /* Make sure that async I/O starts disabled.  */
+  async_io_enabled = 1;
+  disable_async_io ();
+
+  /* Make sure the signal is unblocked.  */
+  unblock_async_io ();
+}
+
 /* Returns next char from remote GDB.  -1 if error.  */
 
 static int
@@ -722,7 +743,7 @@ readchar (void)
 
   bufp = buf;
   bufcnt--;
-  return *bufp++ & 0x7f;
+  return *bufp++;
 }
 
 /* Read a packet from the remote machine, with error checking,
@@ -773,23 +794,42 @@ 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 (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);
+      write (remote_desc, "+", 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;
@@ -943,7 +983,7 @@ prepare_resume_reply (char *buf, char status, unsigned char sig)
         Since thread support relies on qSymbol support anyway, assume GDB can handle
         threads.  */
 
-      if (using_threads)
+      if (using_threads && !disable_packet_Tthread)
        {
          unsigned int gdb_id_from_wait;
 
@@ -965,6 +1005,13 @@ prepare_resume_reply (char *buf, char status, unsigned char sig)
              old_thread_from_wait = thread_from_wait;
            }
        }
+
+      if (dlls_changed)
+       {
+         strcpy (buf, "library:;");
+         buf += strlen (buf);
+         dlls_changed = 0;
+       }
     }
   /* For W and X, we're done.  */
   *buf++ = 0;
@@ -1042,6 +1089,54 @@ decode_X_packet (char *from, int packet_len, CORE_ADDR *mem_addr_ptr,
   return 0;
 }
 
+/* Decode a qXfer write request.  */
+int
+decode_xfer_write (char *buf, int packet_len, char **annex, 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;
+
+  /* Extract the offset.  */
+  *offset = 0;
+  while ((ch = *buf++) != ':')
+    {
+      *offset = *offset << 4;
+      *offset |= fromhex (ch) & 0x0f;
+    }
+
+  /* Get encoded data.  */
+  packet_len -= buf - *annex;
+  *len = remote_unescape_input ((const gdb_byte *) buf, packet_len,
+                               data, packet_len);
+  return 0;
+}
+
+/* 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;
+}
+
 /* Ask GDB for the address of NAME, and return it in ADDRP if found.
    Returns 1 if the symbol is found, 0 if it is not, -1 on error.  */
 
@@ -1079,15 +1174,34 @@ look_up_one_symbol (const char *name, CORE_ADDR *addrp)
   if (len < 0)
     return -1;
 
+  /* We ought to handle pretty much any packet at this point while we
+     wait for the qSymbol "response".  That requires re-entering the
+     main loop.  For now, this is an adequate approximation; allow
+     GDB to read from memory while it figures out the address of the
+     symbol.  */
+  while (own_buf[0] == 'm')
+    {
+      CORE_ADDR mem_addr;
+      unsigned char *mem_buf;
+      unsigned int mem_len;
+
+      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);
+      free (mem_buf);
+      if (putpkt (own_buf) < 0)
+       return -1;
+      len = getpkt (own_buf);
+      if (len < 0)
+       return -1;
+    }
+  
   if (strncmp (own_buf, "qSymbol:", strlen ("qSymbol:")) != 0)
     {
-      /* Malformed response.  */
-      if (remote_debug)
-       {
-         fprintf (stderr, "Malformed response to qSymbol, ignoring.\n");
-         fflush (stderr);
-       }
-
+      warning ("Malformed response to qSymbol, ignoring: %s\n", own_buf);
       return -1;
     }
 
@@ -1103,8 +1217,8 @@ 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 = xmalloc (sizeof (*sym));
+  sym->name = xstrdup (name);
   sym->addr = *addrp;
   sym->next = symbol_cache;
   symbol_cache = sym;
@@ -1115,7 +1229,7 @@ look_up_one_symbol (const char *name, CORE_ADDR *addrp)
 void
 monitor_output (const char *msg)
 {
-  char *buf = malloc (strlen (msg) * 2 + 2);
+  char *buf = xmalloc (strlen (msg) * 2 + 2);
 
   buf[0] = 'O';
   hexify (buf + 1, msg, 0);
@@ -1123,3 +1237,157 @@ monitor_output (const char *msg)
   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 = xmalloc (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;
+}
+
+void
+buffer_grow (struct buffer *buffer, const char *data, size_t size)
+{
+  char *new_buffer;
+  size_t new_buffer_size;
+
+  if (size == 0)
+    return;
+
+  new_buffer_size = buffer->buffer_size;
+
+  if (new_buffer_size == 0)
+    new_buffer_size = 1;
+
+  while (buffer->used_size + size > new_buffer_size)
+    new_buffer_size *= 2;
+  new_buffer = realloc (buffer->buffer, new_buffer_size);
+  if (!new_buffer)
+    abort ();
+  memcpy (new_buffer + buffer->used_size, data, size);
+  buffer->buffer = new_buffer;
+  buffer->buffer_size = new_buffer_size;
+  buffer->used_size += size;
+}
+
+void
+buffer_free (struct buffer *buffer)
+{
+  if (!buffer)
+    return;
+
+  free (buffer->buffer);
+  buffer->buffer = NULL;
+  buffer->buffer_size = 0;
+  buffer->used_size = 0;
+}
+
+void
+buffer_init (struct buffer *buffer)
+{
+  memset (buffer, 0, sizeof (*buffer));
+}
+
+char*
+buffer_finish (struct buffer *buffer)
+{
+  char *ret = buffer->buffer;
+  buffer->buffer = NULL;
+  buffer->buffer_size = 0;
+  buffer->used_size = 0;
+  return ret;
+}
+
+void
+buffer_xml_printf (struct buffer *buffer, const char *format, ...)
+{
+  va_list ap;
+  const char *f;
+  const char *prev;
+  int percent = 0;
+
+  va_start (ap, format);
+
+  prev = format;
+  for (f = format; *f; f++)
+    {
+      if (percent)
+       {
+         switch (*f)
+           {
+           case 's':
+             {
+               char *p;
+               char *a = va_arg (ap, char *);
+               buffer_grow (buffer, prev, f - prev - 1);
+               p = xml_escape_text (a);
+               buffer_grow_str (buffer, p);
+               free (p);
+               prev = f + 1;
+             }
+             break;
+           }
+         percent = 0;
+       }
+      else if (*f == '%')
+       percent = 1;
+    }
+
+  buffer_grow_str (buffer, prev);
+  va_end (ap);
+}
This page took 0.038875 seconds and 4 git commands to generate.