* breakpoint.c (breakpoint_re_set): #ifdef GET_LONGJMP_TARGET
[deliverable/binutils-gdb.git] / gdb / remote-mips.c
index 599d1ec8873a93581015dac94e6baf13c4e7f69d..7514aa935fb713d814f663399782e963100eb3b3 100644 (file)
@@ -1,5 +1,5 @@
 /* Remote debugging interface for MIPS remote debugging protocol.
-   Copyright 1993, 1994 Free Software Foundation, Inc.
+   Copyright 1993, 1994, 1995 Free Software Foundation, Inc.
    Contributed by Cygnus Support.  Written by Ian Lance Taylor
    <ian@cygnus.com>.
 
@@ -17,7 +17,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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #include "defs.h"
 #include "inferior.h"
@@ -31,87 +31,83 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "remote-utils.h"
 
 #include <signal.h>
+#ifdef ANSI_PROTOTYPES
+#include <stdarg.h>
+#else
 #include <varargs.h>
+#endif
+
+extern char *mips_read_processor_type PARAMS ((void));
+
+extern void mips_set_processor_type_command PARAMS ((char *, int));
+
 \f
 /* Prototypes for local functions.  */
 
-static int
-mips_readchar PARAMS ((int timeout));
+static int mips_readchar PARAMS ((int timeout));
 
-static int
-mips_receive_header PARAMS ((unsigned char *hdr, int *pgarbage, int ch,
-                            int timeout));
+static int mips_receive_header PARAMS ((unsigned char *hdr, int *pgarbage,
+                                       int ch, int timeout));
 
-static int
-mips_receive_trailer PARAMS ((unsigned char *trlr, int *pgarbage, int *pch,
-                             int timeout));
+static int mips_receive_trailer PARAMS ((unsigned char *trlr, int *pgarbage,
+                                        int *pch, int timeout));
 
 static int mips_cksum PARAMS ((const unsigned char *hdr,
                               const unsigned char *data,
                               int len));
 
-static void
-mips_send_packet PARAMS ((const char *s, int get_ack));
+static void mips_send_packet PARAMS ((const char *s, int get_ack));
 
 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 timeout));
+static int mips_request PARAMS ((int cmd, unsigned int addr,
+                                unsigned int data, int *perr, int timeout,
+                                char *buff));
 
-static void
-mips_initialize PARAMS ((void));
+static void mips_initialize PARAMS ((void));
 
-static void
-mips_open PARAMS ((char *name, int from_tty));
+static void mips_open PARAMS ((char *name, int from_tty));
 
-static void
-mips_close PARAMS ((int quitting));
+static void mips_close PARAMS ((int quitting));
 
-static void
-mips_detach PARAMS ((char *args, int from_tty));
+static void mips_detach PARAMS ((char *args, int from_tty));
 
 static void mips_resume PARAMS ((int pid, int step,
                                 enum target_signal siggnal));
 
-static int
-mips_wait PARAMS ((int pid, struct target_waitstatus *status));
+static int mips_wait PARAMS ((int pid, struct target_waitstatus *status));
 
-static int
-mips_map_regno PARAMS ((int regno));
+static int mips_map_regno PARAMS ((int regno));
 
-static void
-mips_fetch_registers PARAMS ((int regno));
+static void mips_fetch_registers PARAMS ((int regno));
 
-static void
-mips_prepare_to_store PARAMS ((void));
+static void mips_prepare_to_store PARAMS ((void));
 
-static void
-mips_store_registers PARAMS ((int regno));
+static void mips_store_registers PARAMS ((int regno));
 
-static int
-mips_fetch_word PARAMS ((CORE_ADDR addr));
+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,
-                         int write, struct target_ops *ignore));
+static int mips_xfer_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len,
+                                    int write, struct target_ops *ignore));
 
-static void
-mips_files_info PARAMS ((struct target_ops *ignore));
+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));
 
-static void
-mips_create_inferior PARAMS ((char *execfile, char *args, char **env));
+static void mips_mourn_inferior PARAMS ((void));
 
-static void
-mips_mourn_inferior PARAMS ((void));
+static void mips_load PARAMS ((char *file, int from_tty));
 
+static int mips_make_srec PARAMS ((char *buffer, int type, CORE_ADDR memaddr,
+                                  unsigned char *myaddr, int len));
+
+static int common_breakpoint PARAMS ((int cmd, CORE_ADDR addr, CORE_ADDR mask,
+                                     char *flags));
 /* A forward declaration.  */
 extern struct target_ops mips_ops;
 \f
@@ -140,7 +136,7 @@ extern struct target_ops mips_ops;
        The value is
                0x40 + seq
        An acknowlegment packet contains the sequence number of the
-       packet being acknowledged plus 1 module 64.  Data packets are
+       packet being acknowledged plus 1 modulo 64.  Data packets are
        transmitted in sequence.  There may only be one outstanding
        unacknowledged data packet at a time.  The sequence numbers
        are independent in each direction.  If an acknowledgement for
@@ -281,28 +277,55 @@ static int mips_need_reply = 0;
 /* Handle used to access serial I/O stream.  */
 static serial_t mips_desc;
 
+/* Counts the number of times the user tried to interrupt the target (usually
+   via ^C.  */
+static int interrupt_count;
+
+/* If non-zero, means that the target is running. */
+static int mips_wait_flag = 0;
+
+/* If non-zero, monitor supports breakpoint commands. */
+static monitor_supports_breakpoints = 0;
+
+/* Data cache header.  */
+
+static DCACHE *mips_dcache;
+
+/* Non-zero means that we've just hit a read or write watchpoint */
+static int hit_watchpoint;
+
 /* 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 void NORETURN
+static NORETURN void
+#ifdef ANSI_PROTOTYPES
+mips_error (char *string, ...)
+#else
 mips_error (va_alist)
      va_dcl
+#endif
 {
   va_list args;
-  char *string;
 
+#ifdef ANSI_PROTOTYPES
+  va_start (args, string);
+#else
+  char *string;
   va_start (args);
+  string = va_arg (args, char *);
+#endif
   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);
+  gdb_flush (gdb_stderr);
 
   /* 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
@@ -316,14 +339,54 @@ mips_error (va_alist)
   return_to_top_level (RETURN_ERROR);
 }
 
+/* Wait until STRING shows up in mips_desc.  Returns 1 if successful, else 0 if
+   timed out.  */
+
+int
+mips_expect (string)
+     char *string;
+{
+  char *p = string;
+  int c;
+
+  immediate_quit = 1;
+  while (1)
+    {
+
+/* Must use SERIAL_READCHAR here cuz mips_readchar would get confused if we
+   were waiting for the TARGET_MONITOR_PROMPT... */
+
+      c = SERIAL_READCHAR (mips_desc, 2);
+
+      if (c == SERIAL_TIMEOUT)
+       return 0;
+
+      if (c == *p++)
+       {       
+         if (*p == '\0')
+           {
+             immediate_quit = 0;
+
+             return 1;
+           }
+       }
+      else
+       {
+         p = string;
+         if (c == *p)
+           p++;
+       }
+    }
+}
+
 /* 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
-   we are debugging on the main console port, and we have somehow
-   dropped out of remote debugging mode.  In this case, we
-   automatically go back in to remote debugging mode.  This is a hack,
-   put in because I can't find any way for a program running on the
-   remote board to terminate without also ending remote debugging
+   returns).  FIXME: If we see the string TARGET_MONITOR_PROMPT from
+   the board, then we are debugging on the main console port, and we
+   have somehow dropped out of remote debugging mode.  In this case,
+   we automatically go back in to remote debugging mode.  This is a
+   hack, put in because I can't find any way for a program running on
+   the remote board to terminate without also ending remote debugging
    mode.  I assume users won't have any trouble with this; for one
    thing, the IDT documentation generally assumes that the remote
    debugging port is not the console port.  This is, however, very
@@ -336,14 +399,30 @@ mips_readchar (timeout)
 {
   int ch;
   static int state = 0;
-  static char nextstate[5] = { '<', 'I', 'D', 'T', '>' };
+  static char nextstate[] = TARGET_MONITOR_PROMPT;
+#ifdef MAINTENANCE_CMDS
+  int i;
+
+  i = timeout;
+  if (i == -1 && watchdog > 0)
+    i = watchdog;
+#endif
 
+  if (state == (sizeof(nextstate) / sizeof(char)))
+    timeout = 1;
   ch = SERIAL_READCHAR (mips_desc, timeout);
+#ifdef MAINTENANCE_CMDS
+  if (ch == SERIAL_TIMEOUT && timeout == -1) /* Watchdog went off */
+    {
+      target_mourn_inferior ();
+      error ("Watchdog has expired.  Target detached.\n");
+    }
+#endif
   if (ch == SERIAL_EOF)
     mips_error ("End of file from remote");
   if (ch == SERIAL_ERROR)
     mips_error ("Error reading from remote: %s", safe_strerror (errno));
-  if (sr_get_debug () > 1)
+  if (remote_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.  */
@@ -353,28 +432,29 @@ mips_readchar (timeout)
        printf_unfiltered ("Timed out in read\n");
     }
 
-  /* If we have seen <IDT> and we either time out, or we see a @
-     (which was echoed from a packet we sent), reset the board as
-     described above.  The first character in a packet after the SYN
-     (which is not echoed) is always an @ unless the packet is more
-     than 64 characters long, which ours never are.  */
+  /* If we have seen TARGET_MONITOR_PROMPT and we either time out, or
+     we see a @ (which was echoed from a packet we sent), reset the
+     board as described above.  The first character in a packet after
+     the SYN (which is not echoed) is always an @ unless the packet is
+     more than 64 characters long, which ours never are.  */
   if ((ch == SERIAL_TIMEOUT || ch == '@')
-      && state == 5
+      && state == (sizeof(nextstate) / sizeof(char))
       && ! mips_initializing)
     {
-      if (sr_get_debug () > 0)
+      if (remote_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.  */
        printf_unfiltered ("Reinitializing MIPS debugging mode\n");
-      SERIAL_WRITE (mips_desc, "\rdb tty0\r", sizeof "\rdb tty0\r" - 1);
-      sleep (1);
 
       mips_need_reply = 0;
       mips_initialize ();
 
       state = 0;
 
-      mips_error ("Remote board reset");
+      /* At this point, about the only thing we can do is abort the command
+        in progress and get back to command level as quickly as possible. */
+
+      error ("Remote board reset, debug protocol re-initialized.");
     }
 
   if (ch == nextstate[state])
@@ -416,15 +496,22 @@ mips_receive_header (hdr, pgarbage, ch, timeout)
                 what the program is outputting, if the debugging is
                 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)
+             if (! mips_initializing || remote_debug > 0)
                {
-                 putchar_unfiltered (ch);
+                 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)
-               mips_error ("Remote debugging protocol failure");
+               mips_error ("Debug protocol failure:  more than %d characters before a sync.", 
+                           mips_syn_garbage);
            }
        }
 
@@ -540,9 +627,6 @@ mips_send_packet (s, get_ack)
      the sequence number we expect in the acknowledgement.  */
   mips_send_seq = (mips_send_seq + 1) % SEQ_MODULOS;
 
-  if (! get_ack)
-    return;
-
   /* We can only have one outstanding data packet, so we just wait for
      the acknowledgement here.  Keep retransmitting the packet until
      we get one, or until we've tried too many times.  */
@@ -551,7 +635,7 @@ mips_send_packet (s, get_ack)
       int garbage;
       int ch;
 
-      if (sr_get_debug () > 0)
+      if (remote_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.  */
@@ -563,6 +647,9 @@ mips_send_packet (s, get_ack)
                        HDR_LENGTH + len + TRLR_LENGTH) != 0)
        mips_error ("write to target failed: %s", safe_strerror (errno));
 
+      if (! get_ack)
+       return;
+
       garbage = 0;
       ch = 0;
       while (1)
@@ -609,7 +696,7 @@ mips_send_packet (s, get_ack)
              != TRLR_GET_CKSUM (trlr))
            continue;
 
-         if (sr_get_debug () > 0)
+         if (remote_debug > 0)
            {
              hdr[HDR_LENGTH] = '\0';
              trlr[TRLR_LENGTH] = '\0';
@@ -682,7 +769,7 @@ mips_receive_packet (buff, throw_error, timeout)
        {
          /* 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)
+         if (remote_debug > 0)
            printf_unfiltered ("Ignoring unexpected ACK\n");
          continue;
        }
@@ -692,7 +779,7 @@ mips_receive_packet (buff, throw_error, timeout)
        {
          /* 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)
+         if (remote_debug > 0)
            printf_unfiltered ("Ignoring sequence number %d (want %d)\n",
                             HDR_GET_SEQ (hdr), mips_receive_seq);
          continue;
@@ -724,7 +811,7 @@ mips_receive_packet (buff, throw_error, timeout)
        {
          /* 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)
+         if (remote_debug > 0)
            printf_unfiltered ("Got new SYN after %d chars (wanted %d)\n",
                             i, len);
          continue;
@@ -742,7 +829,7 @@ mips_receive_packet (buff, throw_error, timeout)
        {
          /* 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)
+         if (remote_debug > 0)
            printf_unfiltered ("Got SYN when wanted trailer\n");
          continue;
        }
@@ -750,7 +837,7 @@ mips_receive_packet (buff, throw_error, timeout)
       if (mips_cksum (hdr, buff, len) == TRLR_GET_CKSUM (trlr))
        break;
 
-      if (sr_get_debug () > 0)
+      if (remote_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.  */
        printf_unfiltered ("Bad checksum; data %d, trailer %d\n",
@@ -770,7 +857,7 @@ mips_receive_packet (buff, throw_error, timeout)
       ack[HDR_LENGTH + TRLR_INDX_CSUM2] = TRLR_SET_CSUM2 (cksum);
       ack[HDR_LENGTH + TRLR_INDX_CSUM3] = TRLR_SET_CSUM3 (cksum);
 
-      if (sr_get_debug () > 0)
+      if (remote_debug > 0)
        {
          ack[HDR_LENGTH + TRLR_LENGTH] = '\0';
          /* Don't use _filtered; we can't deal with a QUIT out of
@@ -788,7 +875,7 @@ mips_receive_packet (buff, throw_error, timeout)
        }
     }
 
-  if (sr_get_debug () > 0)
+  if (remote_debug > 0)
     {
       buff[len] = '\0';
       /* Don't use _filtered; we can't deal with a QUIT out of
@@ -810,7 +897,7 @@ mips_receive_packet (buff, throw_error, timeout)
   ack[HDR_LENGTH + TRLR_INDX_CSUM2] = TRLR_SET_CSUM2 (cksum);
   ack[HDR_LENGTH + TRLR_INDX_CSUM3] = TRLR_SET_CSUM3 (cksum);
 
-  if (sr_get_debug () > 0)
+  if (remote_debug > 0)
     {
       ack[HDR_LENGTH + TRLR_LENGTH] = '\0';
       /* Don't use _filtered; we can't deal with a QUIT out of
@@ -856,20 +943,24 @@ mips_receive_packet (buff, throw_error, timeout)
    target board reports.  */
 
 static int
-mips_request (cmd, addr, data, perr, timeout)
-     char cmd;
+mips_request (cmd, addr, data, perr, timeout, buff)
+     int cmd;
      unsigned int addr;
      unsigned int data;
      int *perr;
      int timeout;
+     char *buff;
 {
-  char buff[DATA_MAXLEN + 1];
+  char myBuff[DATA_MAXLEN + 1];
   int len;
   int rpid;
   char rcmd;
   int rerrflg;
   int rresponse;
-  
+
+  if (buff == (char *) NULL)
+    buff = myBuff;
+
   if (cmd != '\0')
     {
       if (mips_need_reply)
@@ -925,7 +1016,7 @@ mips_initialize_cleanups (arg)
 static void
 mips_initialize ()
 {
-  char cr;
+  char cr, cc;
   char buff[DATA_MAXLEN + 1];
   int err;
   struct cleanup *old_cleanups = make_cleanup (mips_initialize_cleanups, NULL);
@@ -939,40 +1030,81 @@ mips_initialize ()
       return;
     }
 
+  mips_wait_flag = 0;
   mips_initializing = 1;
 
   mips_send_seq = 0;
   mips_receive_seq = 0;
 
-  /* 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';
-  SERIAL_WRITE (mips_desc, &cr, 1);
-
   if (mips_receive_packet (buff, 0, 3) < 0)
     {
       char cc;
+      int i, j;
+      char srec[10];
 
       /* 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);
-      sleep (1);
-      cr = '\r';
-      SERIAL_WRITE (mips_desc, &cr, 1);
+
+      /* Force the system into the IDT monitor.  After this we *should* be at
+        the <IDT> prompt.  */
+
+      for (j = 1; j <= 4; j++)
+       {
+         switch (j)
+           {
+           case 1:             /* First, try sending a break */
+             SERIAL_SEND_BREAK (mips_desc);
+             break;
+           case 2:             /* Then, try a ^C */
+             SERIAL_WRITE (mips_desc, "\003", 1); /* Send a ^C to wake up the monitor */
+             break;
+           case 3:             /* Then, try escaping from download */
+             /* We are possibly in binary download mode, having aborted in the middle
+                of an S-record.  ^C won't work because of binary mode.  The only
+                reliable way out is to send enough termination packets (8 bytes) to
+                fill up and then overflow the largest size S-record (255 bytes in this
+                case).  This amounts to 256/8 + 1 packets.  */
+
+             mips_make_srec (srec, '7', 0, NULL, 0);
+
+             for (i = 1; i <= 33; i++)
+               {
+                 SERIAL_WRITE (mips_desc, srec, 8);
+
+                 if (SERIAL_READCHAR (mips_desc, 0) >= 0)
+                   break;      /* Break immediatly if we get something from
+                                  the board. */
+               }
+             break;
+           case 4:
+             mips_error ("Failed to initialize.");
+           }
+         if (mips_expect ("\015\012<IDT>"))
+           break;
+       }
+
+      SERIAL_WRITE (mips_desc, "db tty0\015", sizeof "db tty0\015" - 1);
+      mips_expect ("db tty0\015\012"); /* Eat the echo */
+
+      SERIAL_WRITE (mips_desc, "\015", sizeof "\015" - 1);
+
+      if (mips_receive_packet (buff, 1, 3) < 0)
+       mips_error ("Failed to initialize (didn't receive packet).");
     }
-  mips_receive_packet (buff, 1, 3);
+
+  if (common_breakpoint ('b', -1, 0, NULL)) /* Clear all breakpoints */
+    monitor_supports_breakpoints = 0; /* Failed, don't use it anymore */
+  else
+    monitor_supports_breakpoints = 1;
 
   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_receive_wait);
+               mips_receive_wait, NULL);
+  set_current_frame (create_new_frame (read_fp (), read_pc ()));
+  select_frame (get_current_frame (), 0);
 }
 
 /* Open a connection to the remote board.  */
@@ -982,6 +1114,8 @@ mips_open (name, from_tty)
      char *name;
      int from_tty;
 {
+  char *ptype;
+
   if (name == 0)
     error (
 "To open a MIPS remote debugging connection, you need to specify what serial\n\
@@ -996,6 +1130,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;
@@ -1004,9 +1147,28 @@ device is attached to the target board (e.g., /dev/ttya).");
 
   if (from_tty)
     printf_unfiltered ("Remote MIPS debugging using %s\n", name);
-  push_target (&mips_ops);     /* Switch to using remote target now */
+
+  /* Switch to using remote target now.  */
+  push_target (&mips_ops);
 
   /* FIXME: Should we call start_remote here?  */
+
+  /* Try to figure out the processor model if possible.  */
+  ptype = mips_read_processor_type ();
+  if (ptype)
+    mips_set_processor_type_command (strsave (ptype), 0);
+
+/* This is really the job of start_remote however, that makes an assumption
+   that the target is about to print out a status message of some sort.  That
+   doesn't happen here (in fact, it may not be possible to get the monitor to
+   send the appropriate packet).  */
+
+  flush_cached_frames ();
+  registers_changed ();
+  stop_pc = read_pc ();
+  set_current_frame (create_new_frame (read_fp (), stop_pc));
+  select_frame (get_current_frame (), 0);
+  print_stack_frame (selected_frame, -1, 1);
 }
 
 /* Close a connection to the remote board.  */
@@ -1023,7 +1185,7 @@ mips_close (quitting)
 
       /* Get the board out of remote debugging mode.  */
       mips_request ('x', (unsigned int) 0, (unsigned int) 0, &err,
-                   mips_receive_wait);
+                   mips_receive_wait, NULL);
 
       SERIAL_CLOSE (mips_desc);
     }
@@ -1040,6 +1202,9 @@ mips_detach (args, from_tty)
     error ("Argument given to \"detach\" when remotely debugging.");
 
   pop_target ();
+
+  mips_close (1);
+
   if (from_tty)
     printf_unfiltered ("Ending remote MIPS debugging.\n");
 }
@@ -1052,16 +1217,21 @@ mips_resume (pid, step, siggnal)
      int pid, step;
      enum target_signal siggnal;
 {
+
+/* start-sanitize-gm */
+#ifndef GENERAL_MAGIC_HACKS
   if (siggnal != TARGET_SIGNAL_0)
     warning
       ("Can't send signals to a remote system.  Try `handle %s ignore'.",
        target_signal_to_name (siggnal));
+#endif /* GENERAL_MAGIC_HACKS */
+/* end-sanitize-gm */
 
   mips_request (step ? 's' : 'c',
                (unsigned int) 1,
-               (unsigned int) 0,
+               (unsigned int) siggnal,
                (int *) NULL,
-               mips_receive_wait);
+               mips_receive_wait, NULL);
 }
 
 /* Return the signal corresponding to SIG, where SIG is the number which
@@ -1093,6 +1263,13 @@ mips_wait (pid, status)
 {
   int rstatus;
   int err;
+  char buff[DATA_MAXLEN];
+  int rpc, rfp, rsp;
+  char flags[20];
+  int nfields;
+
+  interrupt_count = 0;
+  hit_watchpoint = 0;
 
   /* If we have not sent a single step or continue command, then the
      board is waiting for us to do something.  Return a status
@@ -1105,10 +1282,46 @@ mips_wait (pid, status)
     }
 
   /* 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);
+  mips_wait_flag = 1;
+  rstatus = mips_request ('\000', (unsigned int) 0, (unsigned int) 0, &err, -1,
+                         buff);
+  mips_wait_flag = 0;
   if (err)
     mips_error ("Remote failure: %s", safe_strerror (errno));
 
+  nfields = sscanf (buff, "0x%*x %*c 0x%*x 0x%*x 0x%x 0x%x 0x%x 0x%*x %s",
+                   &rpc, &rfp, &rsp, flags);
+
+  /* See if we got back extended status.  If so, pick out the pc, fp, sp, etc... */
+
+  if (nfields == 7 || nfields == 9) 
+    {
+      char buf[MAX_REGISTER_RAW_SIZE];
+
+      store_unsigned_integer (buf, REGISTER_RAW_SIZE (PC_REGNUM), rpc);
+      supply_register (PC_REGNUM, buf);
+
+      store_unsigned_integer (buf, REGISTER_RAW_SIZE (PC_REGNUM), rfp);
+      supply_register (30, buf); /* This register they are avoiding and so it is unnamed */
+
+      store_unsigned_integer (buf, REGISTER_RAW_SIZE (SP_REGNUM), rsp);
+      supply_register (SP_REGNUM, buf);
+
+      store_unsigned_integer (buf, REGISTER_RAW_SIZE (FP_REGNUM), 0);
+      supply_register (FP_REGNUM, buf);
+
+      if (nfields == 9)
+       {
+         int i;
+
+         for (i = 0; i <= 2; i++)
+           if (flags[i] == 'r' || flags[i] == 'w')
+             hit_watchpoint = 1;
+           else if (flags[i] == '\000')
+             break;
+       }
+    }
+
   /* 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.  */
@@ -1181,10 +1394,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, NULL);
+      if (err)
+       mips_error ("Can't read register %d: %s", regno,
+                   safe_strerror (errno));
+    }
 
   {
     char buf[MAX_REGISTER_RAW_SIZE];
@@ -1221,7 +1442,7 @@ mips_store_registers (regno)
 
   mips_request ('R', (unsigned int) mips_map_regno (regno),
                (unsigned int) read_register (regno),
-               &err, mips_receive_wait);
+               &err, mips_receive_wait, NULL);
   if (err)
     mips_error ("Can't write register %d: %s", regno, safe_strerror (errno));
 }
@@ -1236,37 +1457,46 @@ mips_fetch_word (addr)
   int err;
 
   val = mips_request ('d', (unsigned int) addr, (unsigned int) 0, &err,
-                     mips_receive_wait);
+                     mips_receive_wait, NULL);
   if (err)
     {
       /* Data space failed; try instruction space.  */
       val = mips_request ('i', (unsigned int) addr, (unsigned int) 0, &err,
-                         mips_receive_wait);
+                         mips_receive_wait, NULL);
       if (err)
        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,
-               mips_receive_wait);
+  oldcontents = mips_request ('D', (unsigned int) addr, (unsigned int) val,
+                             &err,
+                             mips_receive_wait, NULL);
   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, NULL);
       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,
@@ -1292,6 +1522,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.  */
@@ -1317,9 +1549,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
     {
@@ -1353,6 +1600,41 @@ mips_files_info (ignore)
 static void
 mips_kill ()
 {
+  if (!mips_wait_flag)
+    return;
+
+  interrupt_count++;
+
+  if (interrupt_count >= 2)
+    {
+      interrupt_count = 0;
+
+      target_terminal_ours ();
+
+      if (query ("Interrupted while waiting for the program.\n\
+Give up (and stop debugging it)? "))
+       {
+         /* 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_wait_flag = 0;
+         mips_is_open = 0;
+         SERIAL_CLOSE (mips_desc);
+
+         printf_unfiltered ("Ending remote MIPS debugging.\n");
+         target_mourn_inferior ();
+
+         return_to_top_level (RETURN_QUIT);
+       }
+
+      target_terminal_inferior ();
+    }
+
+  if (remote_debug > 0)
+    printf_unfiltered ("Sending break\n");
+
+  SERIAL_SEND_BREAK (mips_desc);
+
 #if 0
   if (mips_is_open)
     {
@@ -1378,10 +1660,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);
 
@@ -1389,7 +1676,16 @@ mips_create_inferior (execfile, args, env)
 
   /* FIXME: Should we set inferior_pid here?  */
 
+/* start-sanitize-gm */
+#ifdef GENERAL_MAGIC_HACKS
+  magic_create_inferior_hook ();
+  proceed (entry_pt, TARGET_SIGNAL_PWR, 0);
+#else
+/* end-sanitize-gm */
   proceed (entry_pt, TARGET_SIGNAL_DEFAULT, 0);
+/* start-sanitize-gm */
+#endif
+/* end-sanitize-gm */
 }
 
 /* Clean up after a process.  Actually nothing to do.  */
@@ -1401,6 +1697,410 @@ 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;
+
+  if (monitor_supports_breakpoints)
+    return common_breakpoint ('B', addr, 0x3, "f");
+
+  return mips_store_word (addr, BREAK_INSN, contents_cache);
+}
+
+static int
+mips_remove_breakpoint (addr, contents_cache)
+     CORE_ADDR addr;
+     char *contents_cache;
+{
+  if (monitor_supports_breakpoints)
+    return common_breakpoint ('b', addr, 0, NULL);
+
+  return target_write_memory (addr, contents_cache, BREAK_INSN_SIZE);
+}
+
+/* Compute a don't care mask for the region bounding ADDR and ADDR + LEN - 1.
+   This is used for memory ref breakpoints.  */
+
+static unsigned long
+calculate_mask (addr, len)
+     CORE_ADDR addr;
+     int len;
+{
+  unsigned long mask;
+  int i;
+
+  mask = addr ^ (addr + len - 1);
+
+  for (i = 32; i >= 0; i--)
+    if (mask == 0)
+      break;
+    else
+      mask >>= 1;
+
+  mask = (unsigned long) 0xffffffff >> i;
+
+  return mask;
+}
+
+/* Set a data watchpoint.  ADDR and LEN should be obvious.  TYPE is either 1
+   for a read watchpoint, or 2 for a read/write watchpoint. */
+
+int
+remote_mips_set_watchpoint (addr, len, type)
+     CORE_ADDR addr;
+     int len;
+     int type;
+{
+  CORE_ADDR first_addr;
+  unsigned long mask;
+  char *flags;
+
+  mask = calculate_mask (addr, len);
+
+  first_addr = addr & ~mask;
+
+  switch (type)
+    {
+    case 0:                    /* write */
+      flags = "w";
+      break;
+    case 1:                    /* read */
+      flags = "r";
+      break;
+    case 2:                    /* read/write */
+      flags = "rw";
+      break;
+    default:
+      abort ();
+    }
+
+  if (common_breakpoint ('B', first_addr, mask, flags))
+    return -1;
+
+  return 0;
+}
+
+int
+remote_mips_remove_watchpoint (addr, len, type)
+     CORE_ADDR addr;
+     int len;
+     int type;
+{
+  CORE_ADDR first_addr;
+  unsigned long mask;
+
+  mask = calculate_mask (addr, len);
+
+  first_addr = addr & ~mask;
+
+  if (common_breakpoint ('b', first_addr, 0, NULL))
+    return -1;
+
+  return 0;
+}
+
+int
+remote_mips_stopped_by_watchpoint ()
+{
+  return hit_watchpoint;
+}
+
+/* This routine generates the a breakpoint command of the form:
+
+   0x0 <CMD> <ADDR> <MASK> <FLAGS>
+
+   Where <CMD> is one of: `B' to set, or `b' to clear a breakpoint.  <ADDR> is
+   the address of the breakpoint.  <MASK> is a don't care mask for addresses.
+   <FLAGS> is any combination of `r', `w', or `f' for read/write/or fetch.  */
+
+static int
+common_breakpoint (cmd, addr, mask, flags)
+     int cmd;
+     CORE_ADDR addr;
+     CORE_ADDR mask;
+     char *flags;
+{
+  int len;
+  char buf[DATA_MAXLEN + 1];
+  char rcmd;
+  int rpid, rerrflg, rresponse;
+  int nfields;
+
+  if (flags)
+    sprintf (buf, "0x0 %c 0x%x 0x%x %s", cmd, addr, mask, flags);
+  else
+    sprintf (buf, "0x0 %c 0x%x", cmd, addr);
+
+  mips_send_packet (buf, 1);
+
+  len = mips_receive_packet (buf, 1, mips_receive_wait);
+
+  nfields = sscanf (buf, "0x%x %c 0x%x 0x%x", &rpid, &rcmd, &rerrflg, &rresponse);
+
+  if (nfields != 4
+      || rcmd != cmd)
+    mips_error ("common_breakpoint: Bad response from remote board: %s", buf);
+
+  if (rerrflg != 0)
+    {
+      if (rerrflg != EINVAL)
+       fprintf_unfiltered (stderr, "common_breakpoint (0x%x):  Got error: 0x%x\n",
+                           addr, rresponse);
+      return 1;
+    }
+
+  return 0;
+}
+\f
+static void
+send_srec (srec, len, addr)
+     char *srec;
+     int len;
+     CORE_ADDR addr;
+{
+  while (1)
+    {
+      int ch;
+
+      SERIAL_WRITE (mips_desc, srec, len);
+
+      ch = mips_readchar (2);
+
+      switch (ch)
+       {
+       case SERIAL_TIMEOUT:
+         error ("Timeout during download.");
+         break;
+       case 0x6:               /* ACK */
+         return;
+       case 0x15:              /* NACK */
+         fprintf_unfiltered (gdb_stderr, "Download got a NACK at byte %d!  Retrying.\n", addr);
+         continue;
+       default:
+         error ("Download got unexpected ack char: 0x%x, retrying.\n", ch);
+       }
+    }
+}
+
+/*  Download a binary file by converting it to S records. */
+
+static void
+mips_load_srec (args)
+     char *args;
+{
+  bfd *abfd;
+  asection *s;
+  char *buffer, srec[1024];
+  int i;
+  int srec_frame = 200;
+  int reclen;
+  static int hashmark = 1;
+
+  buffer = alloca (srec_frame * 2 + 256);
+
+  abfd = bfd_openr (args, 0);
+  if (!abfd)
+    {
+      printf_filtered ("Unable to open file %s\n", args);
+      return;
+    }
+
+  if (bfd_check_format (abfd, bfd_object) == 0)
+    {
+      printf_filtered ("File is not an object file\n");
+      return;
+    }
+  
+#define LOAD_CMD "load -b -s tty0\015"
+
+  SERIAL_WRITE (mips_desc, LOAD_CMD, sizeof LOAD_CMD - 1);
+
+  mips_expect (LOAD_CMD);
+  mips_expect ("\012");
+
+  for (s = abfd->sections; s; s = s->next)
+    {
+      if (s->flags & SEC_LOAD)
+       {
+         int numbytes;
+
+         printf_filtered ("%s\t: 0x%4x .. 0x%4x  ", s->name, s->vma,
+                          s->vma + s->_raw_size);
+         gdb_flush (gdb_stdout);
+
+         for (i = 0; i < s->_raw_size; i += numbytes)
+           {
+             numbytes = min (srec_frame, s->_raw_size - i);
+
+             bfd_get_section_contents (abfd, s, buffer, i, numbytes);
+
+             reclen = mips_make_srec (srec, '3', s->vma + i, buffer, numbytes);
+             send_srec (srec, reclen, s->vma + i);
+
+             if (hashmark)
+               {
+                 putchar_unfiltered ('#');
+                 gdb_flush (gdb_stdout);
+               }
+
+           } /* Per-packet (or S-record) loop */
+         
+         putchar_unfiltered ('\n');
+       } /* Loadable sections */
+    }
+  if (hashmark) 
+    putchar_unfiltered ('\n');
+  
+  /* Write a type 7 terminator record. no data for a type 7, and there
+     is no data, so len is 0.  */
+
+  reclen = mips_make_srec (srec, '7', abfd->start_address, NULL, 0);
+
+  send_srec (srec, reclen, abfd->start_address);
+
+  SERIAL_FLUSH_INPUT (mips_desc);
+}
+
+/*
+ * mips_make_srec -- make an srecord. This writes each line, one at a
+ *     time, each with it's own header and trailer line.
+ *     An srecord looks like this:
+ *
+ * byte count-+     address
+ * start ---+ |        |       data        +- checksum
+ *         | |        |                   |
+ *       S01000006F6B692D746573742E73726563E4
+ *       S315000448600000000000000000FC00005900000000E9
+ *       S31A0004000023C1400037DE00F023604000377B009020825000348D
+ *       S30B0004485A0000000000004E
+ *       S70500040000F6
+ *
+ *     S<type><length><address><data><checksum>
+ *
+ *      Where
+ *      - length
+ *        is the number of bytes following upto the checksum. Note that
+ *        this is not the number of chars following, since it takes two
+ *        chars to represent a byte.
+ *      - type
+ *        is one of:
+ *        0) header record
+ *        1) two byte address data record
+ *        2) three byte address data record
+ *        3) four byte address data record
+ *        7) four byte address termination record
+ *        8) three byte address termination record
+ *        9) two byte address termination record
+ *       
+ *      - address
+ *        is the start address of the data following, or in the case of
+ *        a termination record, the start address of the image
+ *      - data
+ *        is the data.
+ *      - checksum
+ *       is the sum of all the raw byte data in the record, from the length
+ *        upwards, modulo 256 and subtracted from 255.
+ *
+ * This routine returns the length of the S-record.
+ *
+ */
+
+static int
+mips_make_srec (buf, type, memaddr, myaddr, len)
+     char *buf;
+     int type;
+     CORE_ADDR memaddr;
+     unsigned char *myaddr;
+     int len;
+{
+  unsigned char checksum;
+  int i;
+
+  /* Create the header for the srec. addr_size is the number of bytes in the address,
+     and 1 is the number of bytes in the count.  */
+
+  buf[0] = 'S';
+  buf[1] = type;
+  buf[2] = len + 4 + 1;                /* len + 4 byte address + 1 byte checksum */
+  buf[3] = memaddr >> 24;
+  buf[4] = memaddr >> 16;
+  buf[5] = memaddr >> 8;
+  buf[6] = memaddr;
+  memcpy (&buf[7], myaddr, len);
+
+/* Note that the checksum is calculated on the raw data, not the hexified
+   data.  It includes the length, address and the data portions of the
+   packet.  */
+
+  checksum = 0;
+  buf += 2;                    /* Point at length byte */
+  for (i = 0; i < len + 4 + 1; i++)
+    checksum += *buf++;
+
+  *buf = ~checksum;
+
+  return len + 8;
+}
+
+/* mips_load -- download a file. */
+
+static void
+mips_load (file, from_tty)
+    char *file;
+    int  from_tty;
+{
+  int err;
+
+  /* Get the board out of remote debugging mode.  */
+
+  mips_request ('x', (unsigned int) 0, (unsigned int) 0, &err,
+               mips_receive_wait, NULL);
+
+  if (!mips_expect ("\015\012") || !mips_expect (TARGET_MONITOR_PROMPT))
+    error ("mips_load:  Couldn't get into monitor mode.");
+
+  mips_load_srec (file);
+
+  SERIAL_WRITE (mips_desc, "\015db tty0\015", sizeof "\015db tty0\015" - 1);
+
+  mips_initialize ();
+
+/* Finally, make the PC point at the start address */
+
+  if (exec_bfd)
+    write_pc (bfd_get_start_address (exec_bfd));
+
+  inferior_pid = 0;            /* No process now */
+
+/* This is necessary because many things were based on the PC at the time that
+   we attached to the monitor, which is no longer valid now that we have loaded
+   new code (and just changed the PC).  Another way to do this might be to call
+   normal_stop, except that the stack may not be valid, and things would get
+   horribly confused... */
+
+  clear_symtab_users ();
+}
+\f
 /* The target vector.  */
 
 struct target_ops mips_ops =
@@ -1422,20 +2122,22 @@ HOST:PORT to access a board over a network",  /* 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 */
   NULL,                                /* to_terminal_ours */
   NULL,                                /* to_terminal_info */
   mips_kill,                   /* to_kill */
-  generic_load,                        /* to_load */
+  mips_load,                   /* to_load */
   NULL,                                /* to_lookup_symbol */
   mips_create_inferior,                /* to_create_inferior */
   mips_mourn_inferior,         /* to_mourn_inferior */
   NULL,                                /* to_can_run */
   NULL,                                /* to_notice_signals */
+  0,                           /* to_thread_alive */
+  0,                           /* to_stop */
   process_stratum,             /* to_stratum */
   NULL,                                /* to_next */
   1,                           /* to_has_all_memory */
This page took 0.038987 seconds and 4 git commands to generate.