* corelow.c, exec.c, inftarg.c, m3-nat.c, op50-rom.c, procfs.c,
[deliverable/binutils-gdb.git] / gdb / remote-mips.c
index 6f60284edc421e52947cfb5f73c2549c1c55ee4c..0123dbd3d716836d7013b4c6fc4a8102da78465f 100644 (file)
@@ -1,5 +1,5 @@
 /* Remote debugging interface for MIPS remote debugging protocol.
-   Copyright 1993 Free Software Foundation, Inc.
+   Copyright 1993, 1994 Free Software Foundation, Inc.
    Contributed by Cygnus Support.  Written by Ian Lance Taylor
    <ian@cygnus.com>.
 
@@ -31,6 +31,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "remote-utils.h"
 
 #include <signal.h>
+#include <varargs.h>
 \f
 /* Prototypes for local functions.  */
 
@@ -52,12 +53,12 @@ static int mips_cksum PARAMS ((const unsigned char *hdr,
 static void
 mips_send_packet PARAMS ((const char *s, int get_ack));
 
-static int
-mips_receive_packet PARAMS ((char *buff));
+static int mips_receive_packet PARAMS ((char *buff, int throw_error,
+                                       int timeout));
 
 static int
 mips_request PARAMS ((char cmd, unsigned int addr, unsigned int data,
-                     int *perr));
+                     int *perr, int timeout));
 
 static void
 mips_initialize PARAMS ((void));
@@ -71,11 +72,11 @@ mips_close PARAMS ((int quitting));
 static void
 mips_detach PARAMS ((char *args, int from_tty));
 
-static void
-mips_resume PARAMS ((int pid, int step, int siggnal));
+static void mips_resume PARAMS ((int pid, int step,
+                                enum target_signal siggnal));
 
 static int
-mips_wait PARAMS ((int pid, WAITTYPE *status));
+mips_wait PARAMS ((int pid, struct target_waitstatus *status));
 
 static int
 mips_map_regno PARAMS ((int regno));
@@ -92,8 +93,8 @@ mips_store_registers PARAMS ((int regno));
 static int
 mips_fetch_word PARAMS ((CORE_ADDR addr));
 
-static void
-mips_store_word PARAMS ((CORE_ADDR addr, int value));
+static int
+mips_store_word PARAMS ((CORE_ADDR addr, int value, char *old_contents));
 
 static int
 mips_xfer_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len,
@@ -102,9 +103,6 @@ mips_xfer_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len,
 static void
 mips_files_info PARAMS ((struct target_ops *ignore));
 
-static void
-mips_load PARAMS ((char *args, int from_tty));
-
 static void
 mips_create_inferior PARAMS ((char *execfile, char *args, char **env));
 
@@ -280,6 +278,41 @@ static int mips_need_reply = 0;
 /* Handle used to access serial I/O stream.  */
 static serial_t mips_desc;
 
+/* Handle low-level error that we can't recover from.  Note that just
+   error()ing out from target_wait or some such low-level place will cause
+   all hell to break loose--the rest of GDB will tend to get left in an
+   inconsistent state.  */
+
+static NORETURN void
+mips_error (va_alist)
+     va_dcl
+{
+  va_list args;
+  char *string;
+
+  va_start (args);
+  target_terminal_ours ();
+  wrap_here("");                       /* Force out any buffered output */
+  gdb_flush (gdb_stdout);
+  if (error_pre_print)
+    fprintf_filtered (gdb_stderr, error_pre_print);
+  string = va_arg (args, char *);
+  vfprintf_filtered (gdb_stderr, string, args);
+  fprintf_filtered (gdb_stderr, "\n");
+  va_end (args);
+
+  /* Clean up in such a way that mips_close won't try to talk to the
+     board (it almost surely won't work since we weren't able to talk to
+     it).  */
+  mips_is_open = 0;
+  SERIAL_CLOSE (mips_desc);
+
+  printf_unfiltered ("Ending remote MIPS debugging.\n");
+  target_mourn_inferior ();
+
+  return_to_top_level (RETURN_ERROR);
+}
+
 /* Read a character from the remote, aborting on error.  Returns
    SERIAL_TIMEOUT on timeout (since that's what SERIAL_READCHAR
    returns).  FIXME: If we see the string "<IDT>" from the board, then
@@ -302,17 +335,21 @@ mips_readchar (timeout)
   static int state = 0;
   static char nextstate[5] = { '<', 'I', 'D', 'T', '>' };
 
+  if (state == 5) 
+    timeout = 1;
   ch = SERIAL_READCHAR (mips_desc, timeout);
   if (ch == SERIAL_EOF)
-    error ("End of file from remote");
+    mips_error ("End of file from remote");
   if (ch == SERIAL_ERROR)
-    error ("Error reading from remote: %s", safe_strerror (errno));
+    mips_error ("Error reading from remote: %s", safe_strerror (errno));
   if (sr_get_debug () > 1)
     {
+      /* Don't use _filtered; we can't deal with a QUIT out of
+        target_wait, and I think this might be called from there.  */
       if (ch != SERIAL_TIMEOUT)
-       printf_filtered ("Read '%c' %d 0x%x\n", ch, ch, ch);
+       printf_unfiltered ("Read '%c' %d 0x%x\n", ch, ch, ch);
       else
-       printf_filtered ("Timed out in read\n");
+       printf_unfiltered ("Timed out in read\n");
     }
 
   /* If we have seen <IDT> and we either time out, or we see a @
@@ -325,8 +362,10 @@ mips_readchar (timeout)
       && ! mips_initializing)
     {
       if (sr_get_debug () > 0)
-       printf_filtered ("Reinitializing MIPS debugging mode\n");
-      SERIAL_WRITE (mips_desc, "\rdb tty0\r", sizeof "\rdb tty0\r" - 1);
+       /* Don't use _filtered; we can't deal with a QUIT out of
+          target_wait, and I think this might be called from there.  */
+       printf_unfiltered ("Reinitializing MIPS debugging mode\n");
+      SERIAL_WRITE (mips_desc, "\015db tty0\015", sizeof "\015db tty0\015" - 1);
       sleep (1);
 
       mips_need_reply = 0;
@@ -334,7 +373,7 @@ mips_readchar (timeout)
 
       state = 0;
 
-      error ("Remote board reset");
+      mips_error ("Remote board reset");
     }
 
   if (ch == nextstate[state])
@@ -374,17 +413,23 @@ mips_receive_header (hdr, pgarbage, ch, timeout)
            {
              /* Printing the character here lets the user of gdb see
                 what the program is outputting, if the debugging is
-                being done on the console port.  FIXME: Perhaps this
-                should be filtered?  */
+                being done on the console port.  Don't use _filtered;
+                we can't deal with a QUIT out of target_wait.  */
              if (! mips_initializing || sr_get_debug () > 0)
                {
-                 putchar (ch);
-                 fflush (stdout);
+                 if (ch < 0x20 && ch != '\n')
+                   {
+                     putchar_unfiltered ('^');
+                     putchar_unfiltered (ch + 0x40);
+                   }
+                 else
+                   putchar_unfiltered (ch);
+                 gdb_flush (gdb_stdout);
                }
 
              ++*pgarbage;
              if (*pgarbage > mips_syn_garbage)
-               error ("Remote debugging protocol failure");
+               mips_error ("Remote debugging protocol failure");
            }
        }
 
@@ -480,7 +525,7 @@ mips_send_packet (s, get_ack)
 
   len = strlen (s);
   if (len > DATA_MAXLEN)
-    error ("MIPS protocol data packet too long: %s", s);
+    mips_error ("MIPS protocol data packet too long: %s", s);
 
   packet = (unsigned char *) alloca (HDR_LENGTH + len + TRLR_LENGTH + 1);
 
@@ -513,13 +558,15 @@ mips_send_packet (s, get_ack)
 
       if (sr_get_debug () > 0)
        {
+         /* Don't use _filtered; we can't deal with a QUIT out of
+            target_wait, and I think this might be called from there.  */
          packet[HDR_LENGTH + len + TRLR_LENGTH] = '\0';
-         printf_filtered ("Writing \"%s\"\n", packet + 1);
+         printf_unfiltered ("Writing \"%s\"\n", packet + 1);
        }
 
       if (SERIAL_WRITE (mips_desc, packet,
                        HDR_LENGTH + len + TRLR_LENGTH) != 0)
-       error ("write to target failed: %s", safe_strerror (errno));
+       mips_error ("write to target failed: %s", safe_strerror (errno));
 
       garbage = 0;
       ch = 0;
@@ -571,7 +618,9 @@ mips_send_packet (s, get_ack)
            {
              hdr[HDR_LENGTH] = '\0';
              trlr[TRLR_LENGTH] = '\0';
-             printf_filtered ("Got ack %d \"%s%s\"\n",
+             /* Don't use _filtered; we can't deal with a QUIT out of
+                target_wait, and I think this might be called from there.  */
+             printf_unfiltered ("Got ack %d \"%s%s\"\n",
                               HDR_GET_SEQ (hdr), hdr + 1, trlr);
            }
 
@@ -592,18 +641,21 @@ mips_send_packet (s, get_ack)
        }
     }
 
-  error ("Remote did not acknowledge packet");
+  mips_error ("Remote did not acknowledge packet");
 }
 
 /* Receive and acknowledge a packet, returning the data in BUFF (which
    should be DATA_MAXLEN + 1 bytes).  The protocol documentation
    implies that only the sender retransmits packets, so this code just
    waits silently for a packet.  It returns the length of the received
-   packet.  */
+   packet.  If THROW_ERROR is nonzero, call error() on errors.  If not,
+   don't print an error message and return -1.  */
 
 static int
-mips_receive_packet (buff)
+mips_receive_packet (buff, throw_error, timeout)
      char *buff;
+     int throw_error;
+     int timeout;
 {
   int ch;
   int garbage;
@@ -620,24 +672,33 @@ mips_receive_packet (buff)
       int i;
       int err;
 
-      if (mips_receive_header (hdr, &garbage, ch, mips_receive_wait) != 0)
-       error ("Timed out waiting for remote packet");
+      if (mips_receive_header (hdr, &garbage, ch, timeout) != 0)
+       {
+         if (throw_error)
+           mips_error ("Timed out waiting for remote packet");
+         else
+           return -1;
+       }
 
       ch = 0;
 
       /* An acknowledgement is probably a duplicate; ignore it.  */
       if (! HDR_IS_DATA (hdr))
        {
+         /* Don't use _filtered; we can't deal with a QUIT out of
+            target_wait, and I think this might be called from there.  */
          if (sr_get_debug () > 0)
-           printf_filtered ("Ignoring unexpected ACK\n");
+           printf_unfiltered ("Ignoring unexpected ACK\n");
          continue;
        }
 
       /* If this is the wrong sequence number, ignore it.  */
       if (HDR_GET_SEQ (hdr) != mips_receive_seq)
        {
+         /* Don't use _filtered; we can't deal with a QUIT out of
+            target_wait, and I think this might be called from there.  */
          if (sr_get_debug () > 0)
-           printf_filtered ("Ignoring sequence number %d (want %d)\n",
+           printf_unfiltered ("Ignoring sequence number %d (want %d)\n",
                             HDR_GET_SEQ (hdr), mips_receive_seq);
          continue;
        }
@@ -648,32 +709,46 @@ mips_receive_packet (buff)
        {
          int rch;
 
-         rch = mips_readchar (mips_receive_wait);
+         rch = mips_readchar (timeout);
          if (rch == SYN)
            {
              ch = SYN;
              break;
            }
          if (rch == SERIAL_TIMEOUT)
-           error ("Timed out waiting for remote packet");
+           {
+             if (throw_error)
+               mips_error ("Timed out waiting for remote packet");
+             else
+               return -1;
+           }
          buff[i] = rch;
        }
 
       if (i < len)
        {
+         /* Don't use _filtered; we can't deal with a QUIT out of
+            target_wait, and I think this might be called from there.  */
          if (sr_get_debug () > 0)
-           printf_filtered ("Got new SYN after %d chars (wanted %d)\n",
+           printf_unfiltered ("Got new SYN after %d chars (wanted %d)\n",
                             i, len);
          continue;
        }
 
-      err = mips_receive_trailer (trlr, &garbage, &ch, mips_receive_wait);
+      err = mips_receive_trailer (trlr, &garbage, &ch, timeout);
       if (err == -1)
-       error ("Timed out waiting for packet");
+       {
+         if (throw_error)
+           mips_error ("Timed out waiting for packet");
+         else
+           return -1;
+       }
       if (err == -2)
        {
+         /* Don't use _filtered; we can't deal with a QUIT out of
+            target_wait, and I think this might be called from there.  */
          if (sr_get_debug () > 0)
-           printf_filtered ("Got SYN when wanted trailer\n");
+           printf_unfiltered ("Got SYN when wanted trailer\n");
          continue;
        }
 
@@ -681,7 +756,9 @@ mips_receive_packet (buff)
        break;
 
       if (sr_get_debug () > 0)
-       printf_filtered ("Bad checksum; data %d, trailer %d\n",
+       /* Don't use _filtered; we can't deal with a QUIT out of
+          target_wait, and I think this might be called from there.  */
+       printf_unfiltered ("Bad checksum; data %d, trailer %d\n",
                         mips_cksum (hdr, buff, len),
                         TRLR_GET_CKSUM (trlr));
 
@@ -701,18 +778,27 @@ mips_receive_packet (buff)
       if (sr_get_debug () > 0)
        {
          ack[HDR_LENGTH + TRLR_LENGTH] = '\0';
-         printf_filtered ("Writing ack %d \"%s\"\n", mips_receive_seq,
+         /* Don't use _filtered; we can't deal with a QUIT out of
+            target_wait, and I think this might be called from there.  */
+         printf_unfiltered ("Writing ack %d \"%s\"\n", mips_receive_seq,
                           ack + 1);
        }
 
       if (SERIAL_WRITE (mips_desc, ack, HDR_LENGTH + TRLR_LENGTH) != 0)
-       error ("write to target failed: %s", safe_strerror (errno));
+       {
+         if (throw_error)
+           mips_error ("write to target failed: %s", safe_strerror (errno));
+         else
+           return -1;
+       }
     }
 
   if (sr_get_debug () > 0)
     {
       buff[len] = '\0';
-      printf_filtered ("Got packet \"%s\"\n", buff);
+      /* Don't use _filtered; we can't deal with a QUIT out of
+        target_wait, and I think this might be called from there.  */
+      printf_unfiltered ("Got packet \"%s\"\n", buff);
     }
 
   /* We got the packet.  Send an acknowledgement.  */
@@ -732,12 +818,19 @@ mips_receive_packet (buff)
   if (sr_get_debug () > 0)
     {
       ack[HDR_LENGTH + TRLR_LENGTH] = '\0';
-      printf_filtered ("Writing ack %d \"%s\"\n", mips_receive_seq,
+      /* Don't use _filtered; we can't deal with a QUIT out of
+        target_wait, and I think this might be called from there.  */
+      printf_unfiltered ("Writing ack %d \"%s\"\n", mips_receive_seq,
                       ack + 1);
     }
 
   if (SERIAL_WRITE (mips_desc, ack, HDR_LENGTH + TRLR_LENGTH) != 0)
-    error ("write to target failed: %s", safe_strerror (errno));
+    {
+      if (throw_error)
+       mips_error ("write to target failed: %s", safe_strerror (errno));
+      else
+       return -1;
+    }
 
   return len;
 }
@@ -768,11 +861,12 @@ mips_receive_packet (buff)
    target board reports.  */
 
 static int
-mips_request (cmd, addr, data, perr)
+mips_request (cmd, addr, data, perr, timeout)
      char cmd;
      unsigned int addr;
      unsigned int data;
      int *perr;
+     int timeout;
 {
   char buff[DATA_MAXLEN + 1];
   int len;
@@ -798,13 +892,13 @@ mips_request (cmd, addr, data, perr)
 
   mips_need_reply = 0;
 
-  len = mips_receive_packet (buff);
+  len = mips_receive_packet (buff, 1, timeout);
   buff[len] = '\0';
 
   if (sscanf (buff, "0x%x %c 0x%x 0x%x",
              &rpid, &rcmd, &rerrflg, &rresponse) != 4
       || (cmd != '\0' && rcmd != cmd))
-    error ("Bad response from remote board");
+    mips_error ("Bad response from remote board");
 
   if (rerrflg != 0)
     {
@@ -823,6 +917,13 @@ mips_request (cmd, addr, data, perr)
   return rresponse;
 }
 
+static void
+mips_initialize_cleanups (arg)
+     PTR arg;
+{
+  mips_initializing = 0;
+}
+
 /* Initialize a new connection to the MIPS board, and make sure we are
    really connected.  */
 
@@ -830,13 +931,18 @@ static void
 mips_initialize ()
 {
   char cr;
-  int hold_wait;
-  int tries;
   char buff[DATA_MAXLEN + 1];
   int err;
+  struct cleanup *old_cleanups = make_cleanup (mips_initialize_cleanups, NULL);
 
+  /* What is this code doing here?  I don't see any way it can happen, and
+     it might mean mips_initializing didn't get cleared properly.
+     So I'll make it a warning.  */
   if (mips_initializing)
-    return;
+    {
+      warning ("internal error: mips_initialize called twice");
+      return;
+    }
 
   mips_initializing = 1;
 
@@ -846,41 +952,33 @@ mips_initialize ()
   /* The board seems to want to send us a packet.  I don't know what
      it means.  The packet seems to be triggered by a carriage return
      character, although perhaps any character would do.  */
-  cr = '\r';
+  cr = '\015';
+  /* FIXME check the result from this */
   SERIAL_WRITE (mips_desc, &cr, 1);
 
-  hold_wait = mips_receive_wait;
-  mips_receive_wait = 3;
-
-  tries = 0;
-  while (catch_errors (mips_receive_packet, buff, (char *) NULL,
-                      RETURN_MASK_ALL)
-        == 0)
+  if (mips_receive_packet (buff, 0, 3) < 0)
     {
       char cc;
 
-      if (tries > 0)
-       error ("Could not connect to target");
-      ++tries;
-
       /* We did not receive the packet we expected; try resetting the
         board and trying again.  */
       printf_filtered ("Failed to initialize; trying to reset board\n");
       cc = '\003';
       SERIAL_WRITE (mips_desc, &cc, 1);
       sleep (2);
-      SERIAL_WRITE (mips_desc, "\rdb tty0\r", sizeof "\rdb tty0\r" - 1);
+      SERIAL_WRITE (mips_desc, "\015db tty0\015", sizeof "\015db tty0\015" - 1);
       sleep (1);
-      cr = '\r';
+      cr = '\015';
       SERIAL_WRITE (mips_desc, &cr, 1);
     }
+  mips_receive_packet (buff, 1, 3);
 
-  mips_receive_wait = hold_wait;
-  mips_initializing = 0;
+  do_cleanups (old_cleanups);
 
   /* If this doesn't call error, we have connected; we don't care if
      the request itself succeeds or fails.  */
-  mips_request ('r', (unsigned int) 0, (unsigned int) 0, &err);
+  mips_request ('r', (unsigned int) 0, (unsigned int) 0, &err,
+               mips_receive_wait);
 }
 
 /* Open a connection to the remote board.  */
@@ -904,6 +1002,15 @@ device is attached to the target board (e.g., /dev/ttya).");
   if (mips_desc == (serial_t) NULL)
     perror_with_name (name);
 
+  if (baud_rate != -1)
+    {
+      if (SERIAL_SETBAUDRATE (mips_desc, baud_rate))
+        {
+          SERIAL_CLOSE (mips_desc);
+          perror_with_name (name);
+        }
+    }
+
   SERIAL_RAW (mips_desc);
 
   mips_is_open = 1;
@@ -911,7 +1018,7 @@ device is attached to the target board (e.g., /dev/ttya).");
   mips_initialize ();
 
   if (from_tty)
-    printf ("Remote MIPS debugging using %s\n", name);
+    printf_unfiltered ("Remote MIPS debugging using %s\n", name);
   push_target (&mips_ops);     /* Switch to using remote target now */
 
   /* FIXME: Should we call start_remote here?  */
@@ -930,7 +1037,8 @@ mips_close (quitting)
       mips_is_open = 0;
 
       /* Get the board out of remote debugging mode.  */
-      mips_request ('x', (unsigned int) 0, (unsigned int) 0, &err);
+      mips_request ('x', (unsigned int) 0, (unsigned int) 0, &err,
+                   mips_receive_wait);
 
       SERIAL_CLOSE (mips_desc);
     }
@@ -948,7 +1056,7 @@ mips_detach (args, from_tty)
 
   pop_target ();
   if (from_tty)
-    printf ("Ending remote MIPS debugging.\n");
+    printf_unfiltered ("Ending remote MIPS debugging.\n");
 }
 
 /* Tell the target board to resume.  This does not wait for a reply
@@ -956,23 +1064,47 @@ mips_detach (args, from_tty)
 
 static void
 mips_resume (pid, step, siggnal)
-     int pid, step, siggnal;
+     int pid, step;
+     enum target_signal siggnal;
 {
-  if (siggnal)
-    error ("Can't send signals to a remote system.  Try `handle %d ignore'.",
-          siggnal);
+  if (siggnal != TARGET_SIGNAL_0)
+    warning
+      ("Can't send signals to a remote system.  Try `handle %s ignore'.",
+       target_signal_to_name (siggnal));
 
   mips_request (step ? 's' : 'c',
                (unsigned int) 1,
                (unsigned int) 0,
-               (int *) NULL);
+               (int *) NULL,
+               mips_receive_wait);
+}
+
+/* Return the signal corresponding to SIG, where SIG is the number which
+   the MIPS protocol uses for the signal.  */
+enum target_signal
+mips_signal_from_protocol (sig)
+     int sig;
+{
+  /* We allow a few more signals than the IDT board actually returns, on
+     the theory that there is at least *some* hope that perhaps the numbering
+     for these signals is widely agreed upon.  */
+  if (sig <= 0
+      || sig > 31)
+    return TARGET_SIGNAL_UNKNOWN;
+
+  /* Don't want to use target_signal_from_host because we are converting
+     from MIPS signal numbers, not host ones.  Our internal numbers
+     match the MIPS numbers for the signals the board can return, which
+     are: SIGINT, SIGSEGV, SIGBUS, SIGILL, SIGFPE, SIGTRAP.  */
+  return (enum target_signal) sig;
 }
 
 /* Wait until the remote stops, and return a wait status.  */
 
 static int
-mips_wait (status)
-     WAITTYPE *status;
+mips_wait (pid, status)
+     int pid;
+     struct target_waitstatus *status;
 {
   int rstatus;
   int err;
@@ -982,24 +1114,34 @@ mips_wait (status)
      indicating that it is stopped.  */
   if (! mips_need_reply)
     {
-      WSETSTOP (*status, SIGTRAP);
+      status->kind = TARGET_WAITKIND_STOPPED;
+      status->value.sig = TARGET_SIGNAL_TRAP;
       return 0;
     }
 
-  rstatus = mips_request ('\0', (unsigned int) 0, (unsigned int) 0, &err);
+  /* No timeout; we sit here as long as the program continues to execute.  */
+  rstatus = mips_request ('\0', (unsigned int) 0, (unsigned int) 0, &err, -1);
   if (err)
-    error ("Remote failure: %s", safe_strerror (errno));
-
-  /* FIXME: The target board uses numeric signal values which are
-     those used on MIPS systems.  If the host uses different signal
-     values, we need to translate here.  I believe all Unix systems
-     use the same values for the signals the board can return, which
-     are: SIGINT, SIGSEGV, SIGBUS, SIGILL, SIGFPE, SIGTRAP.  */
-
-  /* FIXME: The target board uses a standard Unix wait status int.  If
-     the host system does not, we must translate here.  */
+    mips_error ("Remote failure: %s", safe_strerror (errno));
 
-  *status = rstatus;
+  /* Translate a MIPS waitstatus.  We use constants here rather than WTERMSIG
+     and so on, because the constants we want here are determined by the
+     MIPS protocol and have nothing to do with what host we are running on.  */
+  if ((rstatus & 0377) == 0)
+    {
+      status->kind = TARGET_WAITKIND_EXITED;
+      status->value.integer = (((rstatus) >> 8) & 0377);
+    }
+  else if ((rstatus & 0377) == 0177)
+    {
+      status->kind = TARGET_WAITKIND_STOPPED;
+      status->value.sig = mips_signal_from_protocol (((rstatus) >> 8) & 0377);
+    }
+  else
+    {
+      status->kind = TARGET_WAITKIND_SIGNALLED;
+      status->value.sig = mips_signal_from_protocol (rstatus & 0177);
+    }
 
   return 0;
 }
@@ -1044,7 +1186,7 @@ static void
 mips_fetch_registers (regno)
      int regno;
 {
-  REGISTER_TYPE val;
+  unsigned LONGEST val;
   int err;
 
   if (regno == -1)
@@ -1054,10 +1196,18 @@ mips_fetch_registers (regno)
       return;
     }
 
-  val = mips_request ('r', (unsigned int) mips_map_regno (regno),
-                     (unsigned int) 0, &err);
-  if (err)
-    error ("Can't read register %d: %s", regno, safe_strerror (errno));
+  if (regno == FP_REGNUM || regno == ZERO_REGNUM)
+    /* FP_REGNUM on the mips is a hack which is just supposed to read
+       zero (see also mips-nat.c).  */
+    val = 0;
+  else
+    {
+      val = mips_request ('r', (unsigned int) mips_map_regno (regno),
+                         (unsigned int) 0, &err, mips_receive_wait);
+      if (err)
+       mips_error ("Can't read register %d: %s", regno,
+                   safe_strerror (errno));
+    }
 
   {
     char buf[MAX_REGISTER_RAW_SIZE];
@@ -1094,9 +1244,9 @@ mips_store_registers (regno)
 
   mips_request ('R', (unsigned int) mips_map_regno (regno),
                (unsigned int) read_register (regno),
-               &err);
+               &err, mips_receive_wait);
   if (err)
-    error ("Can't write register %d: %s", regno, safe_strerror (errno));
+    mips_error ("Can't write register %d: %s", regno, safe_strerror (errno));
 }
 
 /* Fetch a word from the target board.  */
@@ -1108,34 +1258,47 @@ mips_fetch_word (addr)
   int val;
   int err;
 
-  val = mips_request ('d', (unsigned int) addr, (unsigned int) 0, &err);
+  val = mips_request ('d', (unsigned int) addr, (unsigned int) 0, &err,
+                     mips_receive_wait);
   if (err)
     {
       /* Data space failed; try instruction space.  */
-      val = mips_request ('i', (unsigned int) addr, (unsigned int) 0, &err);
+      val = mips_request ('i', (unsigned int) addr, (unsigned int) 0, &err,
+                         mips_receive_wait);
       if (err)
-       error ("Can't read address 0x%x: %s", addr, safe_strerror (errno));
+       mips_error ("Can't read address 0x%x: %s", addr, safe_strerror (errno));
     }
   return val;
 }
 
-/* Store a word to the target board.  */
+/* Store a word to the target board.  Returns errno code or zero for
+   success.  If OLD_CONTENTS is non-NULL, put the old contents of that
+   memory location there.  */
 
-static void
-mips_store_word (addr, val)
+static int
+mips_store_word (addr, val, old_contents)
      CORE_ADDR addr;
      int val;
+     char *old_contents;
 {
   int err;
+  unsigned int oldcontents;
 
-  mips_request ('D', (unsigned int) addr, (unsigned int) val, &err);
+  oldcontents = mips_request ('D', (unsigned int) addr, (unsigned int) val,
+                             &err,
+                             mips_receive_wait);
   if (err)
     {
       /* Data space failed; try instruction space.  */
-      mips_request ('I', (unsigned int) addr, (unsigned int) val, &err);
+      oldcontents = mips_request ('I', (unsigned int) addr,
+                                 (unsigned int) val, &err,
+                                 mips_receive_wait);
       if (err)
-       error ("Can't write address 0x%x: %s", addr, safe_strerror (errno));
+       return errno;
     }
+  if (old_contents != NULL)
+    store_unsigned_integer (old_contents, 4, oldcontents);
+  return 0;
 }
 
 /* Read or write LEN bytes from inferior memory at MEMADDR,
@@ -1161,6 +1324,8 @@ mips_xfer_memory (memaddr, myaddr, len, write, ignore)
   /* Allocate buffer of that many longwords.  */
   register char *buffer = alloca (count * 4);
 
+  int status;
+
   if (write)
     {
       /* Fill start and end extra bytes of buffer with existing data.  */
@@ -1186,9 +1351,24 @@ mips_xfer_memory (memaddr, myaddr, len, write, ignore)
 
       for (i = 0; i < count; i++, addr += 4)
        {
-         mips_store_word (addr, extract_unsigned_integer (&buffer[i*4], 4));
+         status = mips_store_word (addr,
+                                   extract_unsigned_integer (&buffer[i*4], 4),
+                                   NULL);
+         /* Report each kilobyte (we download 32-bit words at a time) */
+         if (i % 256 == 255) 
+           {
+             printf_unfiltered ("*");
+             fflush (stdout);
+           }
+         if (status)
+           {
+             errno = status;
+             return 0;
+           }
          /* FIXME: Do we want a QUIT here?  */
        }
+      if (count >= 256)
+       printf_unfiltered ("\n");
     }
   else
     {
@@ -1211,7 +1391,7 @@ static void
 mips_files_info (ignore)
      struct target_ops *ignore;
 {
-  printf ("Debugging a MIPS board over a serial line.\n");
+  printf_unfiltered ("Debugging a MIPS board over a serial line.\n");
 }
 
 /* Kill the process running on the board.  This will actually only
@@ -1247,10 +1427,15 @@ mips_create_inferior (execfile, args, env)
   CORE_ADDR entry_pt;
 
   if (args && *args)
-    error ("Can't pass arguments to remote MIPS board.");
+    {
+      warning ("\
+Can't pass arguments to remote MIPS board; arguments ignored.");
+      /* And don't try to use them on the next "run" command.  */
+      execute_command ("set args", 0);
+    }
 
   if (execfile == 0 || exec_bfd == 0)
-    error ("No exec file specified");
+    error ("No executable file specified");
 
   entry_pt = (CORE_ADDR) bfd_get_start_address (exec_bfd);
 
@@ -1258,7 +1443,7 @@ mips_create_inferior (execfile, args, env)
 
   /* FIXME: Should we set inferior_pid here?  */
 
-  proceed (entry_pt, -1, 0);
+  proceed (entry_pt, TARGET_SIGNAL_DEFAULT, 0);
 }
 
 /* Clean up after a process.  Actually nothing to do.  */
@@ -1270,14 +1455,51 @@ mips_mourn_inferior ()
   generic_mourn_inferior ();
 }
 \f
+/* We can write a breakpoint and read the shadow contents in one
+   operation.  */
+
+/* The IDT board uses an unusual breakpoint value, and sometimes gets
+   confused when it sees the usual MIPS breakpoint instruction.  */
+
+#define BREAK_INSN (0x00000a0d)
+#define BREAK_INSN_SIZE (4)
+
+/* Insert a breakpoint on targets that don't have any better breakpoint
+   support.  We read the contents of the target location and stash it,
+   then overwrite it with a breakpoint instruction.  ADDR is the target
+   location in the target machine.  CONTENTS_CACHE is a pointer to 
+   memory allocated for saving the target contents.  It is guaranteed
+   by the caller to be long enough to save sizeof BREAKPOINT bytes (this
+   is accomplished via BREAKPOINT_MAX).  */
+
+static int
+mips_insert_breakpoint (addr, contents_cache)
+     CORE_ADDR addr;
+     char *contents_cache;
+{
+  int status;
+
+  return mips_store_word (addr, BREAK_INSN, contents_cache);
+}
+
+static int
+mips_remove_breakpoint (addr, contents_cache)
+     CORE_ADDR addr;
+     char *contents_cache;
+{
+  return target_write_memory (addr, contents_cache, BREAK_INSN_SIZE);
+}
+\f
 /* The target vector.  */
 
 struct target_ops mips_ops =
 {
   "mips",                      /* to_shortname */
   "Remote MIPS debugging over serial line",    /* to_longname */
-  "Debug a board using the MIPS remote debugging protocol over a serial line.\n\
-Specify the serial device it is connected to (e.g., /dev/ttya).",  /* to_doc */
+  "\
+Debug a board using the MIPS remote debugging protocol over a serial line.\n\
+The argument is the device it is connected to or, if it contains a colon,\n\
+HOST:PORT to access a board over a network",  /* to_doc */
   mips_open,                   /* to_open */
   mips_close,                  /* to_close */
   NULL,                                /* to_attach */
@@ -1289,8 +1511,8 @@ Specify the serial device it is connected to (e.g., /dev/ttya).",  /* to_doc */
   mips_prepare_to_store,       /* to_prepare_to_store */
   mips_xfer_memory,            /* to_xfer_memory */
   mips_files_info,             /* to_files_info */
-  NULL,                                /* to_insert_breakpoint */
-  NULL,                                /* to_remove_breakpoint */
+  mips_insert_breakpoint,      /* to_insert_breakpoint */
+  mips_remove_breakpoint,      /* to_remove_breakpoint */
   NULL,                                /* to_terminal_init */
   NULL,                                /* to_terminal_inferior */
   NULL,                                /* to_terminal_ours_for_output */
@@ -1303,6 +1525,7 @@ Specify the serial device it is connected to (e.g., /dev/ttya).",  /* to_doc */
   mips_mourn_inferior,         /* to_mourn_inferior */
   NULL,                                /* to_can_run */
   NULL,                                /* to_notice_signals */
+  0,                           /* to_stop */
   process_stratum,             /* to_stratum */
   NULL,                                /* to_next */
   1,                           /* to_has_all_memory */
This page took 0.03416 seconds and 4 git commands to generate.