* remote-utils.c [USE_WIN32API] (read, write): Define.
[deliverable/binutils-gdb.git] / gdb / gdbserver / remote-utils.c
index c36570239f84f72a49aa14214d82b6edf6c3f15c..751f63a5f748a24a42a628b8624dfb5854646b4f 100644 (file)
@@ -1,7 +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
-   Free Software Foundation, Inc.
+   Copyright (C) 1986, 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+   2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
    Boston, MA 02110-1301, USA.  */
 
 #include "server.h"
+#if HAVE_TERMINAL_H
 #include "terminal.h"
+#endif
 #include <stdio.h>
 #include <string.h>
+#if HAVE_SYS_IOCTL_H
 #include <sys/ioctl.h>
+#endif
 #include <sys/file.h>
+#if HAVE_NETINET_IN_H
 #include <netinet/in.h>
+#endif
+#if HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
+#endif
+#if HAVE_NETDB_H
 #include <netdb.h>
+#endif
+#if HAVE_NETINET_TCP_H
 #include <netinet/tcp.h>
+#endif
+#if HAVE_SYS_IOCTL_H
 #include <sys/ioctl.h>
+#endif
 #include <signal.h>
 #include <fcntl.h>
 #include <sys/time.h>
 #include <unistd.h>
+#if HAVE_ARPA_INET_H
 #include <arpa/inet.h>
+#endif
+#include <sys/stat.h>
+#include <errno.h>
+
+#if USE_WIN32API
+#include <winsock.h>
+#endif
 
 #ifndef HAVE_SOCKLEN_T
 typedef int socklen_t;
@@ -52,6 +73,10 @@ struct sym_cache
 /* 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;
 
@@ -61,17 +86,39 @@ static int remote_desc;
 extern int using_threads;
 extern int debug_threads;
 
+#ifdef USE_WIN32API
+# define read(fd, buf, len) recv (fd, buf, len, 0)
+# define write(fd, buf, len) send (fd, buf, len, 0)
+#endif
+
 /* 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;
-  
-  if (!strchr (name, ':'))
+#endif
+  char *port_str;
+
+  port_str = strchr (name, ':');
+  if (port_str == NULL)
     {
-      remote_desc = open (name, O_RDWR);
+#ifdef USE_WIN32API
+      error ("Only <host>:<port> is supported on this platform.");
+#else
+      struct stat statbuf;
+
+      if (stat (name, &statbuf) == 0
+         && (S_ISCHR (statbuf.st_mode) || S_ISFIFO (statbuf.st_mode)))
+       remote_desc = open (name, O_RDWR);
+      else
+       {
+         errno = EINVAL;
+         remote_desc = -1;
+       }
+
       if (remote_desc < 0)
        perror_with_name ("Could not open remote device");
 
@@ -120,9 +167,13 @@ remote_open (char *name)
 #endif
 
       fprintf (stderr, "Remote debugging using %s\n", name);
+#endif /* USE_WIN32API */
     }
   else
     {
+#ifdef USE_WIN32API
+      static int winsock_initialized;
+#endif
       char *port_str;
       int port;
       struct sockaddr_in sockaddr;
@@ -133,7 +184,17 @@ remote_open (char *name)
 
       port = atoi (port_str + 1);
 
-      tmp_desc = socket (PF_INET, SOCK_STREAM, 0);
+#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");
 
@@ -151,6 +212,7 @@ remote_open (char *name)
        perror_with_name ("Can't bind address");
 
       fprintf (stderr, "Listening on port %d\n", port);
+      fflush (stderr);
 
       tmp = sizeof (sockaddr);
       remote_desc = accept (tmp_desc, (struct sockaddr *) &sockaddr, &tmp);
@@ -167,10 +229,15 @@ remote_open (char *name)
       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", 
@@ -190,7 +257,11 @@ remote_open (char *name)
 void
 remote_close (void)
 {
+#ifdef USE_WIN32API
+  closesocket (remote_desc);
+#else
   close (remote_desc);
+#endif
 }
 
 /* Convert hex digit A to a number.  */
@@ -226,7 +297,7 @@ unhexify (char *bin, const char *hex, int count)
   return i;
 }
 
-static void
+void
 decode_address (CORE_ADDR *addrp, const char *start, int len)
 {
   CORE_ADDR addr;
@@ -243,6 +314,22 @@ decode_address (CORE_ADDR *addrp, const char *start, int len)
   *addrp = addr;
 }
 
+const char *
+decode_address_to_semicolon (CORE_ADDR *addrp, const char *start)
+{
+  const char *end;
+
+  end = start;
+  while (*end != '\0' && *end != ';')
+    end++;
+
+  decode_address (addrp, start, end - start);
+
+  if (*end == ';')
+    end++;
+  return end;
+}
+
 /* Convert number NIB to a hex digit.  */
 
 static int
@@ -272,17 +359,142 @@ hexify (char *hex, const char *bin, int count)
   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.");
+
+  return output_index;
+}
+
+/* Look for a sequence of characters which can be run-length encoded.
+   If there are any, update *CSUM and *P.  Otherwise, output the
+   single character.  Return the number of characters consumed.  */
+
+static int
+try_rle (char *buf, int remaining, unsigned char *csum, char **p)
+{
+  int n;
+
+  /* Always output the character.  */
+  *csum += buf[0];
+  *(*p)++ = buf[0];
+
+  /* Don't go past '~'.  */
+  if (remaining > 97)
+    remaining = 97;
+
+  for (n = 1; n < remaining; n++)
+    if (buf[n] != buf[0])
+      break;
+
+  /* N is the index of the first character not the same as buf[0].
+     buf[0] is counted twice, so by decrementing N, we get the number
+     of characters the RLE sequence will replace.  */
+  n--;
+
+  if (n < 3)
+    return 1;
+
+  /* Skip the frame characters.  The manual says to skip '+' and '-'
+     also, but there's no reason to.  Unfortunately these two unusable
+     characters double the encoded length of a four byte zero
+     value.  */
+  while (n + 29 == '$' || n + 29 == '#')
+    n--;
+
+  *csum += '*';
+  *(*p)++ = '*';
+  *csum += n + 29;
+  *(*p)++ = n + 29;
+
+  return n + 1;
+}
+
 /* Send a packet to the remote machine, with error checking.
-   The data of the packet is in BUF.  Returns >= 0 on success, -1 otherwise. */
+   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 (char *buf)
+putpkt_binary (char *buf, int cnt)
 {
   int i;
   unsigned char csum = 0;
   char *buf2;
   char buf3[1];
-  int cnt = strlen (buf);
   char *p;
 
   buf2 = malloc (PBUFSIZ);
@@ -293,11 +505,9 @@ putpkt (char *buf)
   p = buf2;
   *p++ = '$';
 
-  for (i = 0; i < cnt; i++)
-    {
-      csum += buf[i];
-      *p++ = buf[i];
-    }
+  for (i = 0; i < cnt;)
+    i += try_rle (buf + i, cnt - i, &csum, &p);
+
   *p++ = '#';
   *p++ = tohex ((csum >> 4) & 0xf);
   *p++ = tohex (csum & 0xf);
@@ -349,6 +559,18 @@ putpkt (char *buf)
   return 1;                    /* Success! */
 }
 
+/* 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.  */
+
+int
+putpkt (char *buf)
+{
+  return putpkt_binary (buf, strlen (buf));
+}
+
+#ifndef USE_WIN32API
+
 /* 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
@@ -382,29 +604,34 @@ input_interrupt (int unused)
       (*the_target->send_signal) (SIGINT);
     }
 }
+#endif
+
+/* Asynchronous I/O support.  SIGIO must be enabled when waiting, in order to
+   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
 unblock_async_io (void)
 {
+#ifndef USE_WIN32API
   sigset_t sigio_set;
   sigemptyset (&sigio_set);
   sigaddset (&sigio_set, SIGIO);
   sigprocmask (SIG_UNBLOCK, &sigio_set, NULL);
+#endif
 }
 
-/* Asynchronous I/O support.  SIGIO must be enabled when waiting, in order to
-   accept Control-C from the client, and must be disabled when talking to
-   the client.  */
-
 /* Current state of asynchronous I/O.  */
 static int async_io_enabled;
 
@@ -415,7 +642,9 @@ enable_async_io (void)
   if (async_io_enabled)
     return;
 
+#ifndef USE_WIN32API
   signal (SIGIO, input_interrupt);
+#endif
   async_io_enabled = 1;
 }
 
@@ -426,7 +655,9 @@ disable_async_io (void)
   if (!async_io_enabled)
     return;
 
+#ifndef USE_WIN32API
   signal (SIGIO, SIG_IGN);
+#endif
   async_io_enabled = 0;
 }
 
@@ -435,12 +666,12 @@ disable_async_io (void)
 static int
 readchar (void)
 {
-  static char buf[BUFSIZ];
+  static unsigned char buf[BUFSIZ];
   static int bufcnt = 0;
-  static char *bufp;
+  static unsigned char *bufp;
 
   if (bufcnt-- > 0)
-    return *bufp++ & 0x7f;
+    return *bufp++;
 
   bufcnt = read (remote_desc, buf, sizeof (buf));
 
@@ -627,14 +858,12 @@ dead_thread_notify (int id)
 }
 
 void
-prepare_resume_reply (char *buf, char status, unsigned char signo)
+prepare_resume_reply (char *buf, char status, unsigned char sig)
 {
-  int nib, sig;
+  int nib;
 
   *buf++ = status;
 
-  sig = (int)target_signal_from_host (signo);
-
   nib = ((sig & 0xf0) >> 4);
   *buf++ = tohex (nib);
   nib = sig & 0x0f;
@@ -681,9 +910,11 @@ prepare_resume_reply (char *buf, char status, unsigned char signo)
 
       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;
-         unsigned int gdb_id_from_wait = thread_to_gdb_id (current_inferior);
+         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);
@@ -749,6 +980,33 @@ decode_M_packet (char *from, CORE_ADDR *mem_addr_ptr, unsigned int *len_ptr,
   convert_ascii_to_int (&from[i++], to, *len_ptr);
 }
 
+int
+decode_X_packet (char *from, int packet_len, CORE_ADDR *mem_addr_ptr,
+                unsigned int *len_ptr, unsigned char *to)
+{
+  int i = 0;
+  char ch;
+  *mem_addr_ptr = *len_ptr = 0;
+
+  while ((ch = from[i++]) != ',')
+    {
+      *mem_addr_ptr = *mem_addr_ptr << 4;
+      *mem_addr_ptr |= fromhex (ch) & 0x0f;
+    }
+
+  while ((ch = from[i++]) != ':')
+    {
+      *len_ptr = *len_ptr << 4;
+      *len_ptr |= fromhex (ch) & 0x0f;
+    }
+
+  if (remote_unescape_input ((const gdb_byte *) &from[i], packet_len - i,
+                            to, *len_ptr) != *len_ptr)
+    return -1;
+
+  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.  */
 
@@ -767,6 +1025,14 @@ 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 (all_symbols_looked_up)
+    return 0;
+
   /* Send the request.  */
   strcpy (own_buf, "qSymbol:");
   hexify (own_buf + strlen ("qSymbol:"), name, strlen (name));
This page took 0.035036 seconds and 4 git commands to generate.