]> Git Repo - binutils.git/blobdiff - gdb/remote.c
* nlm/gdbserve.c: conditionalize header file inclusion for either
[binutils.git] / gdb / remote.c
index 09eb616d95186f62146479f83a0350b1d28d6b15..fb6184a3f241fe74b1f6dcdc6e9f13069a64ba8e 100644 (file)
@@ -122,12 +122,17 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
        general set     QXXXX=yyyy      Set value of XXXX to yyyy.
        query sect offs qOffsets        Get section offsets.  Reply is
                                        Text=xxx;Data=yyy;Bss=zzz
+       console output  Otext           Send text to stdout.  Only comes from
+                                       remote target.
 
        Responses can be run-length encoded to save space.  A '*' means that
-       the next two characters are hex digits giving a repeat count which
+       the next character is an ASCII encoding giving a repeat count which
        stands for that many repititions of the character preceding the '*'.
-       Note that this means that responses cannot contain '*'.  Example:
-       "0*03" means the same as "0000".  */
+       The encoding is n+29, yielding a printable character where n >=3 
+       (which is where rle starts to win).  Don't use an n > 126.
+
+       So 
+       "0* " means the same as "0000".  */
 
 #include "defs.h"
 #include <string.h>
@@ -145,7 +150,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include "dcache.h"
 
-#if !defined(DONT_USE_REMOTE)
 #ifdef USG
 #include <sys/types.h>
 #endif
@@ -199,7 +203,7 @@ static void
 remote_send PARAMS ((char *buf));
 
 static int
-readchar PARAMS ((void));
+readchar PARAMS ((int timeout));
 
 static int remote_wait PARAMS ((int pid, struct target_waitstatus *status));
 
@@ -227,7 +231,7 @@ extern struct target_ops remote_ops;        /* Forward decl */
    Unless this is going though some terminal server or multiplexer or
    other form of hairy serial connection, I would think 2 seconds would
    be plenty.  */
-static int timeout = 2;
+static int remote_timeout = 2;
 
 #if 0
 int icache;
@@ -280,15 +284,18 @@ remote_close (quitting)
 static void
 get_offsets ()
 {
-  unsigned char buf [PBUFSIZ];
+  unsigned char buf[PBUFSIZ];
   int nvals;
   CORE_ADDR text_addr, data_addr, bss_addr;
   struct section_offsets *offs;
 
   putpkt ("qOffsets");
 
-  getpkt (buf, 1);
+  getpkt (buf, 0);
 
+  if (buf[0] == '\000')
+    return;                    /* Return silently.  Stub doesn't support this
+                                  command. */
   if (buf[0] == 'E')
     {
       warning ("Remote failure reply: %s", buf);
@@ -404,6 +411,15 @@ device is attached to the remote system (e.g. /dev/ttya).");
      stub to another, we can (if the target is closed and reopened) cope.  */
   stub_supports_P = 1;
 
+  /* Without this, some commands which require an active target (such as kill)
+     won't work.  This variable serves (at least) double duty as both the pid
+     of the target process (if it has such), and as a flag indicating that a
+     target is active.  These functions should be split out into seperate
+     variables, especially since GDB will someday have a notion of debugging
+     several processes.  */
+
+  inferior_pid = 42000;
+
   /* Start the remote connection; if error (0), discard this target.
      In particular, if the user quits, be sure to discard it
      (we'd be in an inconsistent state otherwise).  */
@@ -445,7 +461,6 @@ fromhex (a)
     return a - 'a' + 10;
   else
     error ("Reply contains invalid hex digit");
-  return -1;
 }
 
 /* Convert number NIB to a hex digit.  */
@@ -471,7 +486,6 @@ remote_resume (pid, step, siggnal)
 
   if (siggnal)
     {
-      char *name;
       target_terminal_ours_for_output ();
       printf_filtered
        ("Can't send signals to a remote system.  %s not sent.\n",
@@ -556,76 +570,83 @@ remote_wait (pid, status)
       getpkt ((char *) buf, 1);
       signal (SIGINT, ofunc);
 
-      if (buf[0] == 'E')
-       warning ("Remote failure reply: %s", buf);
-      else if (buf[0] == 'T')
+      switch (buf[0])
        {
-         int i;
-         long regno;
-         char regs[MAX_REGISTER_RAW_SIZE];
+       case 'E':               /* Error of some sort */
+         warning ("Remote failure reply: %s", buf);
+         continue;
+       case 'T':               /* Status with PC, SP, FP, ... */
+         {
+           int i;
+           long regno;
+           char regs[MAX_REGISTER_RAW_SIZE];
 
-         /* Expedited reply, containing Signal, {regno, reg} repeat */
-         /*  format is:  'Tssn...:r...;n...:r...;n...:r...;#cc', where
-             ss = signal number
-             n... = register number
-             r... = register contents
-             */
+           /* Expedited reply, containing Signal, {regno, reg} repeat */
+           /*  format is:  'Tssn...:r...;n...:r...;n...:r...;#cc', where
+               ss = signal number
+               n... = register number
+               r... = register contents
+               */
 
-         p = &buf[3];          /* after Txx */
+           p = &buf[3];        /* after Txx */
 
-         while (*p)
-           {
-             unsigned char *p1;
+           while (*p)
+             {
+               unsigned char *p1;
 
-             regno = strtol (p, &p1, 16); /* Read the register number */
+               regno = strtol (p, &p1, 16); /* Read the register number */
 
-             if (p1 == p)
-               warning ("Remote sent badly formed register number: %s\nPacket: '%s'\n",
-                        p1, buf);
+               if (p1 == p)
+                 warning ("Remote sent badly formed register number: %s\nPacket: '%s'\n",
+                          p1, buf);
 
-             p = p1;
+               p = p1;
 
-             if (*p++ != ':')
-               warning ("Malformed packet (missing colon): %s\nPacket: '%s'\n",
-                        p, buf);
+               if (*p++ != ':')
+                 warning ("Malformed packet (missing colon): %s\nPacket: '%s'\n",
+                          p, buf);
 
-             if (regno >= NUM_REGS)
-               warning ("Remote sent bad register number %d: %s\nPacket: '%s'\n",
-                        regno, p, buf);
+               if (regno >= NUM_REGS)
+                 warning ("Remote sent bad register number %d: %s\nPacket: '%s'\n",
+                          regno, p, buf);
 
-             for (i = 0; i < REGISTER_RAW_SIZE (regno); i++)
-               {
-                 if (p[0] == 0 || p[1] == 0)
-                   warning ("Remote reply is too short: %s", buf);
-                 regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]);
-                 p += 2;
-               }
+               for (i = 0; i < REGISTER_RAW_SIZE (regno); i++)
+                 {
+                   if (p[0] == 0 || p[1] == 0)
+                     warning ("Remote reply is too short: %s", buf);
+                   regs[i] = fromhex (p[0]) * 16 + fromhex (p[1]);
+                   p += 2;
+                 }
 
-             if (*p++ != ';')
-               warning ("Remote register badly formatted: %s", buf);
+               if (*p++ != ';')
+                 warning ("Remote register badly formatted: %s", buf);
 
-             supply_register (regno, regs);
-           }
-         break;
-       }
-      else if (buf[0] == 'W')
-       {
-         /* The remote process exited.  */
-         status->kind = TARGET_WAITKIND_EXITED;
-         status->value.integer = (fromhex (buf[1]) << 4) + fromhex (buf[2]);
-         return 0;
+               supply_register (regno, regs);
+             }
+         }
+         /* fall through */
+       case 'S':               /* Old style status, just signal only */
+         status->kind = TARGET_WAITKIND_STOPPED;
+         status->value.sig = (enum target_signal)
+           (((fromhex (buf[1])) << 4) + (fromhex (buf[2])));
+
+         return inferior_pid;
+       case 'W':               /* Target exited */
+         {
+           /* The remote process exited.  */
+           status->kind = TARGET_WAITKIND_EXITED;
+           status->value.integer = (fromhex (buf[1]) << 4) + fromhex (buf[2]);
+           return inferior_pid;
+         }
+       case 'O':               /* Console output */
+         fputs_filtered (buf + 1, gdb_stdout);
+         continue;
+       default:
+         warning ("Invalid remote reply: %s", buf);
+         continue;
        }
-      else if (buf[0] == 'S')
-       break;
-      else
-       warning ("Invalid remote reply: %s", buf);
     }
-
-  status->kind = TARGET_WAITKIND_STOPPED;
-  status->value.sig = (enum target_signal)
-    (((fromhex (buf[1])) << 4) + (fromhex (buf[2])));
-
-  return 0;
+  return inferior_pid;
 }
 
 /* Number of bytes of registers this stub implements.  */
@@ -824,8 +845,8 @@ remote_write_bytes (memaddr, myaddr, len)
   int i;
   char *p;
 
-  /* FIXME-32x64: Need a version of print_address_numeric which doesn't
-     set use_local (and also puts the result in a buffer like sprintf).  */
+  /* FIXME-32x64: Need a version of print_address_numeric which puts the
+     result in a buffer like sprintf.  */
   sprintf (buf, "M%lx,%x:", (unsigned long) memaddr, len);
 
   /* We send target system values byte by byte, in increasing byte addresses,
@@ -875,8 +896,8 @@ remote_read_bytes (memaddr, myaddr, len)
   if (len > PBUFSIZ / 2 - 1)
     abort ();
 
-  /* FIXME-32x64: Need a version of print_address_numeric which doesn't
-     set use_local (and also puts the result in a buffer like sprintf).  */
+  /* FIXME-32x64: Need a version of print_address_numeric which puts the
+     result in a buffer like sprintf.  */
   sprintf (buf, "m%lx,%x", (unsigned long) memaddr, len);
   putpkt (buf);
   getpkt (buf, 0);
@@ -1037,16 +1058,24 @@ remote_files_info (ignore)
 /* Read a single character from the remote end, masking it down to 7 bits. */
 
 static int
-readchar ()
+readchar (timeout)
+     int timeout;
 {
   int ch;
 
   ch = SERIAL_READCHAR (remote_desc, timeout);
 
-  if (ch < 0)
-    return ch;
-
-  return ch & 0x7f;
+  switch (ch)
+    {
+    case SERIAL_EOF:
+      error ("Remote connection closed");
+    case SERIAL_ERROR:
+      perror_with_name ("Remote communication error");
+    case SERIAL_TIMEOUT:
+      return ch;
+    default:
+      return ch & 0x7f;
+    }
 }
 
 /* Send the command in BUF to the remote machine,
@@ -1115,7 +1144,7 @@ putpkt (buf)
       /* read until either a timeout occurs (-2) or '+' is read */
       while (1)
        {
-         ch = readchar ();
+         ch = readchar (remote_timeout);
 
          if (remote_debug)
            {
@@ -1123,8 +1152,6 @@ putpkt (buf)
                {
                case '+':
                case SERIAL_TIMEOUT:
-               case SERIAL_ERROR:
-               case SERIAL_EOF:
                case '$':
                  if (started_error_output)
                    {
@@ -1142,10 +1169,6 @@ putpkt (buf)
              return;
            case SERIAL_TIMEOUT:
              break;            /* Retransmit buffer */
-           case SERIAL_ERROR:
-             perror_with_name ("putpkt: couldn't read ACK");
-           case SERIAL_EOF:
-             error ("putpkt: EOF while trying to read ACK");
            case '$':
              {
                unsigned char junkbuf[PBUFSIZ];
@@ -1185,151 +1208,158 @@ putpkt (buf)
     }
 }
 
+/* Come here after finding the start of the frame.  Collect the rest into BUF,
+   verifying the checksum, length, and handling run-length compression.
+   Returns 0 on any error, 1 on success.  */
+
+static int
+read_frame (buf)
+     char *buf;
+{
+  unsigned char csum;
+  char *bp;
+  int c;
+
+  csum = 0;
+  bp = buf;
+
+  while (1)
+    {
+      c = readchar (remote_timeout);
+
+      switch (c)
+       {
+       case SERIAL_TIMEOUT:
+         if (remote_debug)
+           puts_filtered ("Timeout in mid-packet, retrying\n");
+         return 0;
+       case '$':
+         if (remote_debug)
+           puts_filtered ("Saw new packet start in middle of old one\n");
+         return 0;             /* Start a new packet, count retries */
+       case '#':
+         {
+           unsigned char pktcsum;
+
+           *bp = '\000';
+
+           pktcsum = fromhex (readchar (remote_timeout)) << 4;
+           pktcsum |= fromhex (readchar (remote_timeout));
+
+           if (csum == pktcsum)
+             return 1;
+
+           printf_filtered ("Bad checksum, sentsum=0x%x, csum=0x%x, buf=",
+                            pktcsum, csum);
+           puts_filtered (buf);
+           puts_filtered ("\n");
+
+           return 0;
+         }
+       case '*':               /* Run length encoding */
+         csum += c;
+         c = readchar (remote_timeout);
+         csum += c;
+         c = c - ' ' + 3;      /* Compute repeat count */
+
+         if (bp + c - 1 < buf + PBUFSIZ - 1)
+           {
+             memset (bp, *(bp - 1), c);
+             bp += c;
+             continue;
+           }
+
+         *bp = '\0';
+         printf_filtered ("Repeat count %d too large for buffer: ", c);
+         puts_filtered (buf);
+         puts_filtered ("\n");
+         return 0;
+
+       default:
+         if (bp < buf + PBUFSIZ - 1)
+           {
+             *bp++ = c;
+             csum += c;
+             continue;
+           }
+
+         *bp = '\0';
+         puts_filtered ("Remote packet too long: ");
+         puts_filtered (buf);
+         puts_filtered ("\n");
+
+         return 0;
+       }
+    }
+}
+
 /* Read a packet from the remote machine, with error checking,
    and store it in BUF.  BUF is expected to be of size PBUFSIZ.
    If FOREVER, wait forever rather than timing out; this is used
    while the target is executing user code.  */
 
 static void
-getpkt (retbuf, forever)
-     char *retbuf;
+getpkt (buf, forever)
+     char *buf;
      int forever;
 {
   char *bp;
-  unsigned char csum;
-  int c = 0;
-  unsigned char c1, c2;
-  int retries = 0;
-  char buf[PBUFSIZ];
+  int c;
+  int tries;
+  int timeout;
+  int val;
 
-#define MAX_RETRIES    10
+  if (forever)
+    timeout = -1;
+  else
+    timeout = remote_timeout;
 
-  while (1)
-    {
-#if 0
-      /* This is wrong.  If doing a long backtrace, the user should be
-        able to get out time next we call QUIT, without anything as violent
-        as interrupt_query.  If we want to provide a way out of here
-        without getting to the next QUIT, it should be based on hitting
-        ^C twice as in remote_wait.  */
-      if (quit_flag)
-       {
-         quit_flag = 0;
-         interrupt_query ();
-       }
-#endif
+#define MAX_TRIES 10
 
+  for (tries = 1; tries <= MAX_TRIES; tries++)
+    {
       /* This can loop forever if the remote side sends us characters
         continuously, but if it pauses, we'll get a zero from readchar
         because of timeout.  Then we'll count that as a retry.  */
 
-      c = readchar();
-      if (c > 0 && c != '$')
-       continue;
+      /* Note that we will only wait forever prior to the start of a packet.
+        After that, we expect characters to arrive at a brisk pace.  They
+        should show up within remote_timeout intervals.  */
 
-      if (c == SERIAL_TIMEOUT)
+      do
        {
-         if (forever)
-           continue;
-         if (remote_debug)
-           puts_filtered ("Timed out.\n");
-         goto whole;
-       }
-
-      if (c == SERIAL_EOF)
-       error ("Remote connection closed");
-      if (c == SERIAL_ERROR)
-       perror_with_name ("Remote communication error");
+         c = readchar (timeout);
 
-      /* Force csum to be zero here because of possible error retry.  */
-      csum = 0;
-      bp = buf;
-
-      while (1)
-       {
-         c = readchar ();
          if (c == SERIAL_TIMEOUT)
            {
              if (remote_debug)
-               puts_filtered ("Timeout in mid-packet, retrying\n");
-             goto whole;               /* Start a new packet, count retries */
-           } 
-         if (c == '$')
-           {
-             if (remote_debug)
-               puts_filtered ("Saw new packet start in middle of old one\n");
-             goto whole;               /* Start a new packet, count retries */
+               puts_filtered ("Timed out.\n");
+             goto retry;
            }
-         if (c == '#')
-           break;
-         if (bp >= buf+PBUFSIZ-1)
-         {
-           *bp = '\0';
-           puts_filtered ("Remote packet too long: ");
-           puts_filtered (buf);
-           puts_filtered ("\n");
-           goto whole;
-         }
-         *bp++ = c;
-         csum += c;
        }
-      *bp = 0;
+      while (c != '$');
 
-      c1 = fromhex (readchar ());
-      c2 = fromhex (readchar ());
-      if ((csum & 0xff) == (c1 << 4) + c2)
-       break;
-      printf_filtered ("Bad checksum, sentsum=0x%x, csum=0x%x, buf=",
-             (c1 << 4) + c2, csum & 0xff);
-      puts_filtered (buf);
-      puts_filtered ("\n");
+      /* We've found the start of a packet, now collect the data.  */
 
-      /* Try the whole thing again.  */
-whole:
-      if (++retries < MAX_RETRIES)
-       {
-         SERIAL_WRITE (remote_desc, "-", 1);
-       }
-      else
+      val = read_frame (buf);
+
+      if (val == 1)
        {
-         printf_unfiltered ("Ignoring packet error, continuing...\n");
-         break;
+         if (remote_debug)
+           fprintf_unfiltered (gdb_stderr, "Packet received: %s\n", buf);
+         SERIAL_WRITE (remote_desc, "+", 1);
+         return;
        }
+
+      /* Try the whole thing again.  */
+retry:
+      SERIAL_WRITE (remote_desc, "-", 1);
     }
 
-  /* Deal with run-length encoding.  */
-  {
-    char *src = buf;
-    char *dest = retbuf;
-    int i;
-    int repeat;
-    do {
-      if (*src == '*')
-       {
-         if (src[1] == '\0' || src[2] == '\0')
-           {
-             if (remote_debug)
-               puts_filtered ("Packet too short, retrying\n");
-             goto whole;
-           }
-         repeat = (fromhex (src[1]) << 4) + fromhex (src[2]);
-         for (i = 0; i < repeat; ++i)
-           {
-             *dest++ = src[-1];
-           }
-         src += 2;
-       }
-      else
-       {
-         *dest++ = *src;
-       }
-    } while (*src++ != '\0');
-  }
+  /* We have tried hard enough, and just can't receive the packet.  Give up. */
 
+  printf_unfiltered ("Ignoring packet error, continuing...\n");
   SERIAL_WRITE (remote_desc, "+", 1);
-
-  if (remote_debug)
-    fprintf_unfiltered (gdb_stderr,"Packet received: %s\n", buf);
 }
 \f
 static void
@@ -1441,12 +1471,9 @@ Specify the serial device it is connected to (e.g. /dev/ttya).",  /* to_doc */
   NULL,                                /* sections_end */
   OPS_MAGIC                    /* to_magic */
 };
-#endif /* Use remote.  */
 
 void
 _initialize_remote ()
 {
-#if !defined(DONT_USE_REMOTE)
   add_target (&remote_ops);
-#endif
 }
This page took 0.046429 seconds and 4 git commands to generate.