* inftarg.c (child_thread_alive): New function to see if a
[deliverable/binutils-gdb.git] / gdb / remote-mips.c
index 599d1ec8873a93581015dac94e6baf13c4e7f69d..b49044381e365ad1736fea3c5e35d84e7106abbb 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>.
 
@@ -31,86 +31,74 @@ 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 ((char cmd, unsigned int addr,
+                                unsigned int data, int *perr, int timeout));
 
-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_map_regno PARAMS ((int regno));
+static int mips_wait PARAMS ((int pid, struct target_waitstatus *status));
 
-static void
-mips_fetch_registers PARAMS ((int regno));
+static int mips_map_regno PARAMS ((int regno));
 
-static void
-mips_prepare_to_store PARAMS ((void));
+static void mips_fetch_registers PARAMS ((int regno));
 
-static void
-mips_store_registers PARAMS ((int regno));
+static void mips_prepare_to_store PARAMS ((void));
 
-static int
-mips_fetch_word PARAMS ((CORE_ADDR addr));
+static void mips_store_registers PARAMS ((int regno));
 
-static void
-mips_store_word PARAMS ((CORE_ADDR addr, int value));
+static int mips_fetch_word PARAMS ((CORE_ADDR addr));
 
-static int
-mips_xfer_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len,
-                         int write, struct target_ops *ignore));
+static int mips_store_word PARAMS ((CORE_ADDR addr, int value,
+                                   char *old_contents));
 
-static void
-mips_files_info PARAMS ((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_load PARAMS ((char *args, int from_tty));
+static void mips_files_info PARAMS ((struct target_ops *ignore));
 
-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));
 
 /* A forward declaration.  */
 extern struct target_ops mips_ops;
@@ -140,7 +128,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
@@ -286,20 +274,29 @@ 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
+#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);
@@ -337,8 +334,24 @@ mips_readchar (timeout)
   int ch;
   static int state = 0;
   static char nextstate[5] = { '<', 'I', 'D', 'T', '>' };
+#ifdef MAINTENANCE_CMDS
+  int i;
+
+  i = timeout;
+  if (i == -1 && watchdog > 0)
+    i = watchdog;
+#endif
 
+  if (state == 5) 
+    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)
@@ -366,7 +379,7 @@ mips_readchar (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.  */
        printf_unfiltered ("Reinitializing MIPS debugging mode\n");
-      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);
 
       mips_need_reply = 0;
@@ -374,7 +387,10 @@ mips_readchar (timeout)
 
       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])
@@ -418,7 +434,13 @@ mips_receive_header (hdr, pgarbage, ch, timeout)
                 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);
                }
 
@@ -869,7 +891,7 @@ mips_request (cmd, addr, data, perr, timeout)
   char rcmd;
   int rerrflg;
   int rresponse;
-  
+
   if (cmd != '\0')
     {
       if (mips_need_reply)
@@ -947,7 +969,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)
@@ -960,9 +983,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);
@@ -982,6 +1005,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 +1021,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 +1038,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.  */
@@ -1181,10 +1234,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];
@@ -1248,25 +1309,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,
@@ -1292,6 +1362,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 +1389,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
     {
@@ -1378,10 +1465,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);
 
@@ -1401,6 +1493,41 @@ 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 =
@@ -1422,8 +1549,8 @@ 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 */
@@ -1436,6 +1563,8 @@ HOST:PORT to access a board over a network",  /* to_doc */
   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.028982 seconds and 4 git commands to generate.