* corelow.c, exec.c, inftarg.c, m3-nat.c, op50-rom.c, procfs.c,
[deliverable/binutils-gdb.git] / gdb / remote-mips.c
index 23e89f4a8cf27ad064cd62881576eedfbdfb4169..0123dbd3d716836d7013b4c6fc4a8102da78465f 100644 (file)
@@ -93,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,
@@ -103,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));
 
@@ -286,7 +283,7 @@ static serial_t mips_desc;
    all hell to break loose--the rest of GDB will tend to get left in an
    inconsistent state.  */
 
-static void NORETURN
+static NORETURN void
 mips_error (va_alist)
      va_dcl
 {
@@ -338,6 +335,8 @@ 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)
     mips_error ("End of file from remote");
@@ -345,10 +344,12 @@ mips_readchar (timeout)
     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 @
@@ -361,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;
@@ -410,11 +413,17 @@ 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_unfiltered (ch);
+                 if (ch < 0x20 && ch != '\n')
+                   {
+                     putchar_unfiltered ('^');
+                     putchar_unfiltered (ch + 0x40);
+                   }
+                 else
+                   putchar_unfiltered (ch);
                  gdb_flush (gdb_stdout);
                }
 
@@ -549,8 +558,10 @@ 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,
@@ -607,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);
            }
 
@@ -672,16 +685,20 @@ mips_receive_packet (buff, throw_error, timeout)
       /* 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;
        }
@@ -710,8 +727,10 @@ mips_receive_packet (buff, throw_error, timeout)
 
       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;
        }
@@ -726,8 +745,10 @@ mips_receive_packet (buff, throw_error, timeout)
        }
       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;
        }
 
@@ -735,7 +756,9 @@ mips_receive_packet (buff, throw_error, timeout)
        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));
 
@@ -755,7 +778,9 @@ mips_receive_packet (buff, throw_error, timeout)
       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);
        }
 
@@ -771,7 +796,9 @@ mips_receive_packet (buff, throw_error, timeout)
   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.  */
@@ -791,7 +818,9 @@ mips_receive_packet (buff, throw_error, timeout)
   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);
     }
 
@@ -923,7 +952,8 @@ 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);
 
   if (mips_receive_packet (buff, 0, 3) < 0)
@@ -936,9 +966,9 @@ mips_initialize ()
       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);
@@ -972,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;
@@ -1157,10 +1196,18 @@ mips_fetch_registers (regno)
       return;
     }
 
-  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));
+  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];
@@ -1224,25 +1271,34 @@ mips_fetch_word (addr)
   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,
-               mips_receive_wait);
+  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,
-                   mips_receive_wait);
+      oldcontents = mips_request ('I', (unsigned int) addr,
+                                 (unsigned int) val, &err,
+                                 mips_receive_wait);
       if (err)
-       mips_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,
@@ -1268,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.  */
@@ -1293,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
     {
@@ -1354,10 +1427,15 @@ mips_create_inferior (execfile, args, env)
   CORE_ADDR entry_pt;
 
   if (args && *args)
-    mips_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)
-    mips_error ("No exec file specified");
+    error ("No executable file specified");
 
   entry_pt = (CORE_ADDR) bfd_get_start_address (exec_bfd);
 
@@ -1377,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 */
@@ -1396,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 */
@@ -1410,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.028642 seconds and 4 git commands to generate.