* remote-monitor.c: updated copyright.
authorK. Richard Pixley <rich@cygnus>
Mon, 2 Aug 1993 23:54:27 +0000 (23:54 +0000)
committerK. Richard Pixley <rich@cygnus>
Mon, 2 Aug 1993 23:54:27 +0000 (23:54 +0000)
  (bug_ops, monitor_desc): now static.
  (monitor_desc): in several places, check and/or set to NULL.

* remote-hms.c (hms_files_info): Add the appropriate items where
  missing in the printf call.

* remote-bug.c: new file for m88k bug support.

* config/m88k/m88k.mt (TDEPFILES): added remote-bug.o.

gdb/config/m88k/m88k.mt
gdb/remote-bug.c [new file with mode: 0644]
gdb/remote-hms.c
gdb/remote-monitor.c

index 73e1bed57537ece1e9310d0eccb2ce71ffe86524..f48ea2fe1f309d09545f2f116b08d3135a7b904a 100644 (file)
@@ -1,3 +1,3 @@
 # Target: Motorola 88000 Binary Compatability Standard
-TDEPFILES= m88k-tdep.o m88k-pinsn.o exec.o
+TDEPFILES= m88k-tdep.o m88k-pinsn.o exec.o remote-bug.o
 TM_FILE= tm-m88k.h
diff --git a/gdb/remote-bug.c b/gdb/remote-bug.c
new file mode 100644 (file)
index 0000000..43c4cd3
--- /dev/null
@@ -0,0 +1,1485 @@
+/* Remote debugging interface for Motorola's MVME187BUG monitor, an embedded
+   monitor for the m88k.
+
+   Copyright 1992, 1993 Free Software Foundation, Inc.
+   Contributed by Cygnus Support.  Written by K. Richard Pixley.
+
+This file is part of GDB.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+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.  */
+
+#include "defs.h"
+#include "inferior.h"
+#include "wait.h"
+#include "value.h"
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <errno.h>
+#include "terminal.h"
+#include "target.h"
+#include "gdbcore.h"
+#include "serial.h"
+
+/* External data declarations */
+extern int stop_soon_quietly;  /* for wait_for_inferior */
+
+/* Forward data declarations */
+static struct target_ops bug_ops;      /* Forward declaration */
+
+/* Forward function declarations */
+static void bug_fetch_registers ();
+static int bug_store_registers ();
+static void bug_close ();
+static int bug_clear_breakpoints ();
+
+static int quiet = 1;
+
+
+serial_t desc;
+
+/***********************************************************************/
+/* Caching stuff stolen from remote-nindy.c  */
+
+/* The data cache records all the data read from the remote machine
+   since the last time it stopped.
+
+   Each cache block holds LINE_SIZE bytes of data
+   starting at a multiple-of-LINE_SIZE address.  */
+
+#define LINE_SIZE_POWER 4
+#define LINE_SIZE (1<<LINE_SIZE_POWER) /* eg 1<<3 == 8 */
+#define LINE_SIZE_MASK ((LINE_SIZE-1)) /* eg 7*2+1= 111*/
+#define DCACHE_SIZE 64         /* Number of cache blocks */
+#define XFORM(x)  ((x&LINE_SIZE_MASK)>>2)
+struct dcache_block
+  {
+    struct dcache_block *next, *last;
+    unsigned int addr;         /* Address for which data is recorded.  */
+    int data[LINE_SIZE / sizeof (int)];
+  };
+
+struct dcache_block dcache_free, dcache_valid;
+
+/* Free all the data cache blocks, thus discarding all cached data.  */
+static
+void
+dcache_flush ()
+{
+  register struct dcache_block *db;
+
+  while ((db = dcache_valid.next) != &dcache_valid)
+    {
+      remque (db);
+      insque (db, &dcache_free);
+    }
+}
+
+/*
+ * If addr is present in the dcache, return the address of the block
+ * containing it.
+ */
+static
+struct dcache_block *
+dcache_hit (addr)
+     unsigned int addr;
+{
+  register struct dcache_block *db;
+
+  if (addr & 3)
+    abort ();
+
+  /* Search all cache blocks for one that is at this address.  */
+  db = dcache_valid.next;
+  while (db != &dcache_valid)
+    {
+      if ((addr & ~LINE_SIZE_MASK) == db->addr)
+       return db;
+      db = db->next;
+    }
+  return NULL;
+}
+
+/*  Return the int data at address ADDR in dcache block DC.  */
+static
+int
+dcache_value (db, addr)
+     struct dcache_block *db;
+     unsigned int addr;
+{
+  if (addr & 3)
+    abort ();
+  return (db->data[XFORM (addr)]);
+}
+
+/* Get a free cache block, put or keep it on the valid list,
+   and return its address.  The caller should store into the block
+   the address and data that it describes, then remque it from the
+   free list and insert it into the valid list.  This procedure
+   prevents errors from creeping in if a ninMemGet is interrupted
+   (which used to put garbage blocks in the valid list...).  */
+static
+struct dcache_block *
+dcache_alloc ()
+{
+  register struct dcache_block *db;
+
+  if ((db = dcache_free.next) == &dcache_free)
+    {
+      /* If we can't get one from the free list, take last valid and put
+        it on the free list.  */
+      db = dcache_valid.last;
+      remque (db);
+      insque (db, &dcache_free);
+    }
+
+  remque (db);
+  insque (db, &dcache_valid);
+  return (db);
+}
+
+/* Return the contents of the word at address ADDR in the remote machine,
+   using the data cache.  */
+static
+int
+dcache_fetch (addr)
+     CORE_ADDR addr;
+{
+  register struct dcache_block *db;
+
+  db = dcache_hit (addr);
+  if (db == 0)
+    {
+      db = dcache_alloc ();
+      immediate_quit++;
+      bug_read_inferior_memory (addr & ~LINE_SIZE_MASK, (unsigned char *) db->data, LINE_SIZE);
+      immediate_quit--;
+      db->addr = addr & ~LINE_SIZE_MASK;
+      remque (db);             /* Off the free list */
+      insque (db, &dcache_valid);      /* On the valid list */
+    }
+  return (dcache_value (db, addr));
+}
+
+/* Write the word at ADDR both in the data cache and in the remote machine.  */
+static void
+dcache_poke (addr, data)
+     CORE_ADDR addr;
+     int data;
+{
+  register struct dcache_block *db;
+
+  /* First make sure the word is IN the cache.  DB is its cache block.  */
+  db = dcache_hit (addr);
+  if (db == 0)
+    {
+      db = dcache_alloc ();
+      immediate_quit++;
+      bug_write_inferior_memory (addr & ~LINE_SIZE_MASK, (unsigned char *) db->data, LINE_SIZE);
+      immediate_quit--;
+      db->addr = addr & ~LINE_SIZE_MASK;
+      remque (db);             /* Off the free list */
+      insque (db, &dcache_valid);      /* On the valid list */
+    }
+
+  /* Modify the word in the cache.  */
+  db->data[XFORM (addr)] = data;
+
+  /* Send the changed word.  */
+  immediate_quit++;
+  bug_write_inferior_memory (addr, (unsigned char *) &data, 4);
+  immediate_quit--;
+}
+
+/* The cache itself. */
+struct dcache_block the_cache[DCACHE_SIZE];
+
+/* Initialize the data cache.  */
+static void
+dcache_init ()
+{
+  register i;
+  register struct dcache_block *db;
+
+  db = the_cache;
+  dcache_free.next = dcache_free.last = &dcache_free;
+  dcache_valid.next = dcache_valid.last = &dcache_valid;
+  for (i = 0; i < DCACHE_SIZE; i++, db++)
+    insque (db, &dcache_free);
+}
+
+/***********************************************************************
+ * I/O stuff stolen from remote-eb.c
+ ***********************************************************************/
+
+static int timeout = 2;
+
+static const char *dev_name;
+
+/* Descriptor for I/O to remote machine.  Initialize it to -1 so that
+   bug_open knows that we don't have a file open when the program
+   starts.  */
+
+int is_open = 0;
+int
+check_open ()
+{
+  if (!is_open)
+    {
+      error ("remote device not open");
+    }
+}
+
+#define ON     1
+#define OFF    0
+
+/* Read a character from the remote system, doing all the fancy
+   timeout stuff.  */
+static int
+readchar ()
+{
+  int buf;
+
+  buf = SERIAL_READCHAR (desc, timeout);
+
+  if (buf == SERIAL_TIMEOUT)
+    error ("Timeout reading from remote system.");
+
+  if (!quiet)
+    printf ("%c", buf);
+
+  return buf & 0x7f;
+}
+
+static int
+readchar_nofail ()
+{
+  int buf;
+
+  buf = SERIAL_READCHAR (desc, timeout);
+  if (buf == SERIAL_TIMEOUT)
+    buf = 0;
+  if (!quiet)
+    printf ("%c", buf);
+
+  return buf & 0x7f;
+
+}
+
+/* Keep discarding input from the remote system, until STRING is found.
+   Let the user break out immediately.  */
+static void
+expect (string)
+     char *string;
+{
+  char *p = string;
+
+  immediate_quit = 1;
+  while (1)
+    {
+      if (readchar () == *p)
+       {
+         p++;
+         if (*p == '\0')
+           {
+             immediate_quit = 0;
+             return;
+           }
+       }
+      else
+       p = string;
+    }
+}
+
+/* Keep discarding input until we see the bug prompt.
+
+   The convention for dealing with the prompt is that you
+   o give your command
+   o *then* wait for the prompt.
+
+   Thus the last thing that a procedure does with the serial line
+   will be an expect_prompt().  Exception:  bug_resume does not
+   wait for the prompt, because the terminal is being handed over
+   to the inferior.  However, the next thing which happens after that
+   is a bug_wait which does wait for the prompt.
+   Note that this includes abnormal exit, e.g. error().  This is
+   necessary to prevent getting into states from which we can't
+   recover.  */
+static void
+expect_prompt ()
+{
+  expect ("Bug>");
+}
+
+/* Get a hex digit from the remote system & return its value.
+   If ignore_space is nonzero, ignore spaces (not newline, tab, etc).  */
+static int
+get_hex_digit (ignore_space)
+     int ignore_space;
+{
+  int ch;
+
+  while (1)
+    {
+      ch = readchar ();
+      if (ch >= '0' && ch <= '9')
+       return ch - '0';
+      else if (ch >= 'A' && ch <= 'F')
+       return ch - 'A' + 10;
+      else if (ch >= 'a' && ch <= 'f')
+       return ch - 'a' + 10;
+      else if (ch == ' ' && ignore_space)
+       ;
+      else
+       {
+         expect_prompt ();
+         error ("Invalid hex digit from remote system.");
+       }
+    }
+}
+
+/* Get a byte from bug_desc and put it in *BYT.  Accept any number
+   leading spaces.  */
+static void
+get_hex_byte (byt)
+     char *byt;
+{
+  int val;
+
+  val = get_hex_digit (1) << 4;
+  val |= get_hex_digit (0);
+  *byt = val;
+}
+
+/* Read a 32-bit hex word from the bug, preceded by a space  */
+static long
+get_hex_word ()
+{
+  long val;
+  int j;
+
+  val = 0;
+  for (j = 0; j < 8; j++)
+    val = (val << 4) + get_hex_digit (j == 0);
+  return val;
+}
+
+/* Called when SIGALRM signal sent due to alarm() timeout.  */
+
+/* Number of SIGTRAPs we need to simulate.  That is, the next
+   NEED_ARTIFICIAL_TRAP calls to bug_wait should just return
+   SIGTRAP without actually waiting for anything.  */
+
+static int need_artificial_trap = 0;
+
+void
+bug_kill (arg, from_tty)
+     char *arg;
+     int from_tty;
+{
+
+}
+
+/*
+ * Download a file specified in 'args', to the bug.
+ */
+static void
+bug_load (args, fromtty)
+     char *args;
+     int fromtty;
+{
+  bfd *abfd;
+  asection *s;
+  int n;
+  char buffer[1024];
+
+  check_open ();
+
+  dcache_flush ();
+  inferior_pid = 0;
+  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;
+    }
+
+  s = abfd->sections;
+  while (s != (asection *) NULL)
+    {
+      if (s->flags & SEC_LOAD)
+       {
+         int i;
+
+#define DELTA (1024)
+         char *buffer = xmalloc (DELTA);
+
+         printf_filtered ("%s\t: 0x%4x .. 0x%4x  ", s->name, s->vma, s->vma + s->_raw_size);
+         for (i = 0; i < s->_raw_size; i += DELTA)
+           {
+             int delta = DELTA;
+
+             if (delta > s->_raw_size - i)
+               delta = s->_raw_size - i;
+
+             bfd_get_section_contents (abfd, s, buffer, i, delta);
+             bug_write_inferior_memory (s->vma + i, buffer, delta);
+             printf_filtered ("*");
+             fflush (stdout);
+           }
+         printf_filtered ("\n");
+         free (buffer);
+       }
+      s = s->next;
+    }
+  sprintf (buffer, "rs ip %x", abfd->start_address);
+  bug_write_cr (buffer);
+  expect_prompt ();
+}
+
+/* This is called not only when we first attach, but also when the
+   user types "run" after having attached.  */
+void
+bug_create_inferior (execfile, args, env)
+     char *execfile;
+     char *args;
+     char **env;
+{
+  int entry_pt;
+  char buffer[100];
+
+  if (args && *args)
+    error ("Can't pass arguments to remote bug process.");
+
+  if (execfile == 0 || exec_bfd == 0)
+    error ("No exec file specified");
+
+  entry_pt = (int) bfd_get_start_address (exec_bfd);
+  check_open ();
+
+  bug_kill (NULL, NULL);
+  bug_clear_breakpoints ();
+  init_wait_for_inferior ();
+  bug_write_cr ("");
+  expect_prompt ();
+
+  insert_breakpoints ();       /* Needed to get correct instruction in cache */
+  proceed (entry_pt, -1, 0);
+}
+
+/* Open a connection to a remote debugger.
+   NAME is the filename used for communication, then a space,
+   then the baud rate.
+ */
+
+static char *
+find_end_of_word (s)
+     char *s;
+{
+  while (*s && !isspace (*s))
+    s++;
+  return s;
+}
+
+static char *
+get_word (p)
+     char **p;
+{
+  char *s = *p;
+  char *word;
+  char *copy;
+  size_t len;
+
+  while (isspace (*s))
+    s++;
+
+  word = s;
+
+  len = 0;
+
+  while (*s && !isspace (*s))
+    {
+      s++;
+      len++;
+
+    }
+  copy = xmalloc (len + 1);
+  memcpy (copy, word, len);
+  copy[len] = 0;
+  *p = s;
+  return copy;
+}
+
+static int baudrate = 9600;
+
+#if 0
+static int
+is_baudrate_right ()
+{
+  int ok;
+
+  /* Put this port into NORMAL mode, send the 'normal' character */
+
+  bug_write ("\001", 1);       /* Control A */
+  bug_write ("\r", 1);         /* Cr */
+
+  while (1)
+    {
+      ok = SERIAL_READCHAR (desc, timeout);
+      if (ok < 0)
+       break;
+    }
+
+  bug_write ("r", 1);
+
+  if (readchar_nofail () == 'r')
+    return 1;
+
+  /* Not the right baudrate, or the board's not on */
+  return 0;
+}
+#endif /* not */
+
+static void
+set_rate ()
+{
+  if (!SERIAL_SETBAUDRATE (desc, baudrate))
+    error ("Can't set baudrate");
+}
+
+
+static void
+bug_open (name, from_tty)
+     char *name;
+     int from_tty;
+{
+  unsigned int prl;
+  char *p;
+
+  push_target (&bug_ops);
+
+  if (name == 0)
+    {
+      name = "";
+    }
+  if (is_open)
+    bug_close (0);
+  dev_name = strdup (name);
+
+  if (!(desc = SERIAL_OPEN (dev_name)))
+    perror_with_name ((char *) dev_name);
+
+  SERIAL_RAW (desc);
+  is_open = 1;
+
+  dcache_init ();
+
+  /* Hello?  Are you there?  */
+  SERIAL_WRITE (desc, "\r", 1);
+  expect_prompt ();
+
+  /* Clear any break points */
+  bug_clear_breakpoints ();
+
+  printf_filtered ("Connected to remote 187bug system.\n");
+}
+
+/* Close out all files and local state before this target loses control. */
+
+static void
+bug_close (quitting)
+     int quitting;
+{
+  /* Clear any break points */
+  bug_clear_breakpoints ();
+
+  if (is_open)
+    SERIAL_CLOSE (desc);
+
+  is_open = 0;
+}
+
+/* Terminate the open connection to the remote debugger.
+   Use this when you want to detach and do something else
+   with your gdb.  */
+void
+bug_detach (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  if (is_open)
+    bug_clear_breakpoints ();
+
+  pop_target ();               /* calls bug_close to do the real work */
+
+  if (from_tty)
+    printf_filtered ("Ending remote %s debugging\n", target_shortname);
+}
+
+/* Tell the remote machine to resume.  */
+
+void
+bug_resume (step, sig)
+     int step, sig;
+{
+  dcache_flush ();
+
+  if (step)
+    {
+      bug_write_cr("t");
+
+      /* Force the next bug_wait to return a trap.  Not doing anything
+       about I/O from the target means that the user has to type
+       "continue" to see any.  FIXME, this should be fixed.  */
+      need_artificial_trap = 1;
+    }
+  else
+      bug_write_cr ("g");
+
+  return;
+}
+
+/* Wait until the remote machine stops, then return,
+   storing status in STATUS just as `wait' would.  */
+
+int
+not_bug_wait (status)
+     WAITTYPE *status;
+{
+  int old_timeout;
+  int old_quit;
+  int i;
+
+  expect("Effective address: ");
+  i = get_hex_word();
+  expect("\r");
+
+  WSETEXIT ((*status), 0);
+
+  old_timeout = timeout;
+  timeout = 99999;             /* while user program runs. */
+  old_quit = immediate_quit;
+  immediate_quit = 1; /* helps ability to quit. */
+
+  while (strchr("\n\r", i = readchar()) != NULL) ;;
+
+  immediate_quit = old_quit;
+  timeout = old_timeout;
+
+  if (i == 'A')
+    {
+/* At Breakpoint */
+      expect("t Breakpoint");
+      WSETSTOP ((*status), SIGTRAP);
+
+    }
+  else
+    {
+/* finished cleanly */
+      ;
+    }
+
+  expect_prompt();
+}
+
+int
+bug_wait (status)
+     WAITTYPE *status;
+{
+  /* Strings to look for.  '?' means match any single character.
+     Note that with the algorithm we use, the initial character
+     of the string cannot recur in the string, or we will not
+     find some cases of the string in the input.  */
+
+  static char bpt[] = "At Breakpoint";
+  static char exitmsg[] = "????-Bug>";
+  char *bp = bpt;
+  char *ep = exitmsg;
+
+  /* Large enough for either sizeof (bpt) or sizeof (exitmsg) chars.  */
+  char swallowed[50];
+
+  /* Current position in swallowed.  */
+  char *swallowed_p = swallowed;
+
+  int ch;
+  int ch_handled;
+  int old_timeout = timeout;
+  int old_immediate_quit = immediate_quit;
+  int swallowed_cr = 0;
+
+  WSETEXIT ((*status), 0);
+
+  if (need_artificial_trap != 0)
+    {
+      WSETSTOP ((*status), SIGTRAP);
+      need_artificial_trap--;
+      /* user output from the target can be discarded here. (?) */
+      expect_prompt();
+      return 0;
+    }
+
+  /* read off leftovers from resume */
+  expect("Effective address: ");
+  (void) get_hex_word();
+  while (strchr("\r\n", ch = readchar()) != NULL) ;;
+
+  timeout = 99999;             /* Don't time out -- user program is running. */
+  immediate_quit = 1;          /* Helps ability to QUIT */
+  while (1)
+    {
+      QUIT;                    /* Let user quit and leave process running */
+      ch_handled = 0;
+      if (ch == *bp)
+       {
+         bp++;
+         if (*bp == '\0')
+           break;
+         ch_handled = 1;
+
+         *swallowed_p++ = ch;
+       }
+      else
+       {
+         bp = bpt;
+       }
+      if (ch == *ep || *ep == '?')
+       {
+         ep++;
+         if (*ep == '\0')
+           break;
+
+         if (!ch_handled)
+           *swallowed_p++ = ch;
+         ch_handled = 1;
+       }
+      else
+       {
+         ep = exitmsg;
+       }
+
+      if (!ch_handled)
+       {
+         char *p;
+
+         /* Print out any characters which have been swallowed.  */
+         for (p = swallowed; p < swallowed_p; ++p)
+           putc (*p, stdout);
+         swallowed_p = swallowed;
+
+         if ((ch != '\r' && ch != '\n') || swallowed_cr > 10)
+           {
+             putc (ch, stdout);
+             swallowed_cr = 10;
+           }
+         swallowed_cr++;
+
+       }
+
+      ch = readchar ();
+    }
+  if (*bp == '\0')
+    {
+      WSETSTOP ((*status), SIGTRAP);
+      expect_prompt ();
+    }
+  else
+    {
+      WSETEXIT ((*status), 0);
+    }
+
+  timeout = old_timeout;
+  immediate_quit = old_immediate_quit;
+  return 0;
+}
+
+/* Return the name of register number REGNO
+   in the form input and output by bug.
+
+   Returns a pointer to a static buffer containing the answer.  */
+static char *
+get_reg_name (regno)
+     int regno;
+{
+  static char *rn[] = {
+    "r00", "r01", "r02", "r03", "r04", "r05", "r06", "r07",
+    "r08", "r09", "r10", "r11", "r12", "r13", "r14", "r15",
+    "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+    "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
+
+    /* these get confusing because we omit a few and switch some ordering around. */
+
+    "cr01",  /* 32 = psr */
+    "fcr62", /* 33 = fpsr*/
+    "fcr63", /* 34 = fpcr */
+    "cr04",  /* 35 = sxip */
+    "cr05", /* 36 = snip */
+    "cr06", /* 37 = sfip */
+  };
+
+  return rn[regno];
+}
+
+static int
+gethex (length, start, ok)
+     unsigned int length;
+     char *start;
+     int *ok;
+{
+  int result = 0;
+
+  while (length--)
+    {
+      result <<= 4;
+      if (*start >= 'a' && *start <= 'f')
+       {
+         result += *start - 'a' + 10;
+       }
+      else if (*start >= 'A' && *start <= 'F')
+       {
+         result += *start - 'A' + 10;
+       }
+      else if (*start >= '0' && *start <= '9')
+       {
+         result += *start - '0';
+       }
+      else
+       *ok = 0;
+      start++;
+
+    }
+  return result;
+}
+static int
+timed_read (buf, n, timeout)
+     char *buf;
+
+{
+  int i;
+  char c;
+
+  i = 0;
+  while (i < n)
+    {
+      c = readchar ();
+
+      if (c == 0)
+       return i;
+      buf[i] = c;
+      i++;
+
+    }
+  return i;
+}
+
+bug_write (a, l)
+     char *a;
+{
+  int i;
+
+  SERIAL_WRITE (desc, a, l);
+
+  if (!quiet)
+    for (i = 0; i < l; i++)
+      {
+       printf ("%c", a[i]);
+      }
+}
+
+bug_write_cr (s)
+     char *s;
+{
+  bug_write (s, strlen (s));
+  bug_write ("\r", 1);
+}
+
+/* Store register REGNO, or all if REGNO == -1. */
+
+static void
+bug_fetch_register(regno)
+     int regno;
+{
+  REGISTER_TYPE regval;
+  check_open();
+
+  if (regno == -1)
+    {
+      int i;
+
+      for (i = 0; i < NUM_REGS; ++i)
+       bug_fetch_register(i);
+    }
+  else
+    {
+      bug_write("rs ", 3);
+      bug_write_cr(get_reg_name(regno));
+      expect("=");
+      regval = get_hex_word();
+      expect_prompt();
+
+      /* the following registers contain flag bits in the lower to bit slots.
+        Mask them off */
+      if (regno == PC_REGNUM   /* aka sxip */
+         || regno == NPC_REGNUM /* aka snip */
+         || regno == SFIP_REGNUM)      /* aka sfip */
+       regval &= ~0x3;
+
+      supply_register(regno, (char *) &regval);
+    }
+
+  return;
+}
+
+/* Store register REGNO, or all if REGNO == -1. */
+
+static void
+bug_store_register (regno)
+     int regno;
+{
+  REGISTER_TYPE regval;
+  char buffer[1024];
+  check_open();
+
+  if (regno == -1)
+    {
+      int i;
+
+      for (i = 0; i < NUM_REGS; ++i)
+       bug_store_register(i);
+    }
+  else
+    {
+      char *regname;
+
+      /* get_reg_name thinks that the pc is in sxip.  This is only partially
+        true.  When *assigning* it, we must assign to ip on m88k-bug. */
+
+      regname = ((regno == PC_REGNUM)
+                ? "ip"
+                : get_reg_name(regno));
+
+      sprintf(buffer, "rs %s %08x",
+             regname,
+             read_register(regno));
+
+      bug_write_cr(buffer);
+      expect_prompt();
+    }
+
+  return;
+}
+
+/* Get ready to modify the registers array.  On machines which store
+   individual registers, this doesn't need to do anything.  On machines
+   which store all the registers in one fell swoop, this makes sure
+   that registers contains all the registers from the program being
+   debugged.  */
+
+void
+bug_prepare_to_store ()
+{
+  /* Do nothing, since we can store individual regs */
+}
+
+static CORE_ADDR
+translate_addr (addr)
+     CORE_ADDR addr;
+{
+
+  return (addr);
+
+}
+
+/* Read a word from remote address ADDR and return it.
+ * This goes through the data cache.
+ */
+int
+bug_fetch_word (addr)
+     CORE_ADDR addr;
+{
+  return dcache_fetch (addr);
+}
+
+/* Write a word WORD into remote address ADDR.
+   This goes through the data cache.  */
+
+void
+bug_store_word (addr, word)
+     CORE_ADDR addr;
+     int word;
+{
+  dcache_poke (addr, word);
+}
+
+int
+bug_xfer_inferior_memory (memaddr, myaddr, len, write, target)
+     CORE_ADDR memaddr;
+     char *myaddr;
+     int len;
+     int write;
+     struct target_ops *target;        /* ignored */
+{
+  register int i;
+
+  /* Round starting address down to longword boundary.  */
+  register CORE_ADDR addr;
+
+  /* Round ending address up; get number of longwords that makes.  */
+  register int count;
+
+  /* Allocate buffer of that many longwords.  */
+  register int *buffer;
+
+  addr = memaddr & -sizeof (int);
+  count = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
+
+  buffer = (int *) alloca (count * sizeof (int));
+
+  if (write)
+    {
+      /* Fill start and end extra bytes of buffer with existing memory data.  */
+
+      if (addr != memaddr || len < (int) sizeof (int))
+       {
+         /* Need part of initial word -- fetch it.  */
+         buffer[0] = bug_fetch_word (addr);
+       }
+
+      if (count > 1)           /* FIXME, avoid if even boundary */
+       {
+         buffer[count - 1]
+           = bug_fetch_word (addr + (count - 1) * sizeof (int));
+       }
+
+      /* Copy data to be written over corresponding part of buffer */
+
+      bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len);
+
+      /* Write the entire buffer.  */
+
+      for (i = 0; i < count; i++, addr += sizeof (int))
+       {
+         errno = 0;
+         bug_store_word (addr, buffer[i]);
+         if (errno)
+           {
+
+             return 0;
+           }
+
+       }
+    }
+  else
+    {
+      /* Read all the longwords */
+      for (i = 0; i < count; i++, addr += sizeof (int))
+       {
+         errno = 0;
+         buffer[i] = bug_fetch_word (addr);
+         if (errno)
+           {
+             return 0;
+           }
+         QUIT;
+       }
+
+      /* Copy appropriate bytes out of the buffer.  */
+      bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);
+    }
+
+  return len;
+}
+
+/* fixme: make this user settable */
+#define CHUNK_SIZE (30)
+
+int
+bug_write_inferior_memory (memaddr, myaddr, len)
+     CORE_ADDR memaddr;
+     unsigned char *myaddr;
+     int len;
+{
+  int done;
+  int todo;
+  int checksum;
+  char buffer[(CHUNK_SIZE + 8) << 1];
+
+  done = 0;
+
+#define LOAD_COMMAND "lo 0"
+  bug_write_cr (LOAD_COMMAND);
+
+  while (done < len)
+    {
+      int thisgo;
+      int idx;
+      char *buf = buffer;
+      CORE_ADDR address;
+
+      checksum = 0;
+      thisgo = len - done;
+      if (thisgo > CHUNK_SIZE)
+       thisgo = CHUNK_SIZE;
+
+      address = memaddr + done;
+      sprintf (buf, "S3%02X%08X", thisgo + 4 + 1, address);
+      buf += 12;
+
+      checksum += (thisgo + 4 + 1
+                  + (address & 0xff)
+                  + ((address >>  8) & 0xff)
+                  + ((address >> 16) & 0xff)
+                  + ((address >> 24) & 0xff));
+
+      for (idx = 0; idx < thisgo; idx++)
+       {
+         sprintf (buf, "%02X", myaddr[idx + done]);
+         checksum += myaddr[idx + done];
+         buf += 2;
+       }
+      sprintf(buf, "%02X", ~checksum & 0xff);
+      bug_write_cr (buffer);
+      done += thisgo;
+    }
+
+  bug_write_cr("S7060000000000F9");
+  expect_prompt();
+}
+
+void
+bug_files_info ()
+{
+  char *file = "nothing";
+
+  if (exec_bfd)
+    file = bfd_get_filename (exec_bfd);
+
+  if (exec_bfd)
+#ifdef __GO32__
+    printf_filtered ("\tAttached to DOS asynctsr and running program %s\n", file);
+#else
+    printf_filtered ("\tAttached to %s at %d baud and running program %s\n", dev_name, baudrate, file);
+#endif
+  printf_filtered ("\ton an m88k processor.\n");
+}
+
+/* Copy LEN bytes of data from debugger memory at MYADDR
+   to inferior's memory at MEMADDR.  Returns errno value.
+ * sb/sh instructions don't work on unaligned addresses, when TU=1.
+ */
+
+/* Read LEN bytes from inferior memory at MEMADDR.  Put the result
+   at debugger address MYADDR.  Returns errno value.  */
+int
+bug_read_inferior_memory (memaddr, myaddr, len)
+     CORE_ADDR memaddr;
+     char *myaddr;
+     int len;
+{
+  char request[100];
+  char *buffer;
+  char *p;
+  char type;
+  char size;
+  unsigned char c;
+  unsigned int inaddr;
+  unsigned int checksum;
+
+  sprintf(request, "du 0 %x:&%d", memaddr, len);
+  bug_write_cr(request);
+
+  p = buffer = alloca(len);
+
+  /* scan up through the header */
+  expect("S0030000FC");
+
+  while (p < buffer + len)
+    {
+      /* scan off any white space. */
+      while (readchar() != 'S') ;;
+
+      /* what kind of s-rec? */
+      type = readchar();
+
+      /* scan record size */
+      get_hex_byte(&size);
+      checksum = size;
+      --size;
+      inaddr = 0;
+
+      switch (type)
+       {
+       case '7':
+       case '8':
+       case '9':
+         goto done;
+
+       case '3':
+         get_hex_byte(&c);
+         inaddr = (inaddr << 8) + c;
+         checksum += c;
+         --size;
+         /* intentional fall through */
+       case '2':
+         get_hex_byte(&c);
+         inaddr = (inaddr << 8) + c;
+         checksum += c;
+         --size;
+         /* intentional fall through */
+       case '1':
+         get_hex_byte(&c);
+         inaddr = (inaddr << 8) + c;
+         checksum += c;
+         --size;
+         get_hex_byte(&c);
+         inaddr = (inaddr << 8) + c;
+         checksum += c;
+         --size;
+         break;
+
+       default:
+         /* bonk */
+         error("reading s-records.");
+       }
+
+      if (inaddr < memaddr
+         || (memaddr + len) < (inaddr + size))
+       error("srec out of memory range.");
+
+      if (p != buffer + inaddr - memaddr)
+       error("srec out of sequence.");
+
+      for (; size; --size, ++p)
+       {
+         get_hex_byte(p);
+         checksum += *p;
+       }
+
+      get_hex_byte(&c);
+      if (c != (~checksum & 0xff))
+       error("bad s-rec checksum");
+    }
+
+ done:
+  expect_prompt();
+  if (p != buffer + len)
+    return(1);
+
+  memcpy(myaddr, buffer, len);
+  return(0);
+}
+
+/* This routine is run as a hook, just before the main command loop is
+   entered.  If gdb is configured for the H8, but has not had its
+   target specified yet, this will loop prompting the user to do so.
+*/
+
+bug_before_main_loop ()
+{
+  char ttyname[100];
+  char *p, *p2;
+  extern FILE *instream;
+
+  push_target (&bug_ops);
+}
+
+#define MAX_BREAKS     16
+static int num_brkpts = 0;
+static int
+bug_insert_breakpoint (addr, save)
+     CORE_ADDR addr;
+     char *save;               /* Throw away, let bug save instructions */
+{
+  check_open ();
+
+  if (num_brkpts < MAX_BREAKS)
+    {
+      char buffer[100];
+
+      num_brkpts++;
+      sprintf (buffer, "br %x", addr);
+      bug_write_cr (buffer);
+      expect_prompt ();
+      return(0);
+    }
+  else
+    {
+      fprintf_filtered (stderr,
+                     "Too many break points, break point not installed\n");
+      return(1);
+    }
+
+}
+static int
+bug_remove_breakpoint (addr, save)
+     CORE_ADDR addr;
+     char *save;               /* Throw away, let bug save instructions */
+{
+  if (num_brkpts > 0)
+    {
+      char buffer[100];
+
+      num_brkpts--;
+      sprintf (buffer, "nobr %x", addr);
+      bug_write_cr (buffer);
+      expect_prompt ();
+
+    }
+  return (0);
+}
+
+/* Clear the bugs notion of what the break points are */
+static int
+bug_clear_breakpoints ()
+{
+
+  if (is_open)
+    {
+      bug_write_cr ("nobr");
+      expect_prompt ();
+    }
+  num_brkpts = 0;
+}
+static void
+bug_mourn ()
+{
+  bug_clear_breakpoints ();
+  generic_mourn_inferior ();
+}
+
+/* Put a command string, in args, out to the bug.  The bug is assumed to
+   be in raw mode, all writing/reading done through desc.
+   Ouput from the bug is placed on the users terminal until the
+   prompt from the bug is seen.
+   FIXME: Can't handle commands that take input.  */
+
+void
+bug_com (args, fromtty)
+     char *args;
+     int fromtty;
+{
+  check_open ();
+
+  if (!args)
+    return;
+
+  /* Clear all input so only command relative output is displayed */
+
+  bug_write_cr (args);
+  bug_write ("\030", 1);
+  expect_prompt ();
+}
+
+bug_quiet ()
+{
+  quiet = !quiet;
+  if (quiet)
+    printf_filtered ("Snoop disabled\n");
+  else
+    printf_filtered ("Snoop enabled\n");
+
+}
+
+bug_device (s)
+     char *s;
+{
+  if (s)
+    {
+      dev_name = get_word (&s);
+    }
+}
+
+#if 0
+static
+bug_speed (s)
+     char *s;
+{
+  check_open ();
+
+  if (s)
+    {
+      char buffer[100];
+      int newrate = atoi (s);
+      int which = 0;
+
+      if (SERIAL_SETBAUDRATE (desc, newrate))
+       error ("Can't use %d baud\n", newrate);
+
+      printf_filtered ("Checking target is in sync\n");
+
+      printf_filtered ("Sending commands to set target to %d\n",
+                      baudrate);
+
+      sprintf (buffer, "tm %d. N 8 1", baudrate);
+      bug_write_cr (buffer);
+    }
+}
+#endif /* 0 */
+
+static struct target_ops bug_ops =
+{
+  "bug", "Remote BUG monitor",
+  "Use the mvme187 board running the BUG monitor connected\n\
+by a serial line.",
+
+  bug_open, bug_close,
+  0, bug_detach, bug_resume, bug_wait, /* attach */
+  bug_fetch_register, bug_store_register,
+  bug_prepare_to_store,
+  bug_xfer_inferior_memory,
+  bug_files_info,
+  bug_insert_breakpoint, bug_remove_breakpoint,        /* Breakpoints */
+  0, 0, 0, 0, 0,               /* Terminal handling */
+  bug_kill,                    /* FIXME, kill */
+  bug_load,
+  0,                           /* lookup_symbol */
+  bug_create_inferior,         /* create_inferior */
+  bug_mourn,                   /* mourn_inferior FIXME */
+  0,                           /* can_run */
+  0,                           /* notice_signals */
+  process_stratum, 0,          /* next */
+  1, 1, 1, 1, 1,               /* all mem, mem, stack, regs, exec */
+  0, 0,                                /* Section pointers */
+  OPS_MAGIC,                   /* Always the last thing */
+};
+
+void
+_initialize_remote_bug ()
+{
+  add_target (&bug_ops);
+
+  add_com ("bug <command>", class_obscure, bug_com,
+          "Send a command to the BUG monitor.");
+  add_com ("snoop", class_obscure, bug_quiet,
+          "Show what commands are going to the monitor");
+
+  add_com ("device", class_obscure, bug_device,
+          "Set the terminal line for BUG communications");
+
+#if 0
+  add_com ("speed", class_obscure, bug_speed,
+          "Set the terminal line speed for BUG communications");
+#endif /* 0 */
+
+  dev_name = NULL;
+}
index 92cab9a5200d22bb9df9f3ee79898b6feddbd1ad..22d6c2b121ca85c6510cec71d0c34d5917f66fab 100644 (file)
@@ -1110,7 +1110,7 @@ hms_files_info ()
 #ifdef __GO32__
     printf_filtered ("\tAttached to DOS asynctsr and running program %s\n", file);
 #else
-    printf_filtered ("\tAttached to %s at %d baud and running program %s\n", file);
+    printf_filtered ("\tAttached to %s at %d baud and running program %s\n", dev_name, baudrate, file);
 #endif
   printf_filtered ("\ton an H8/300 processor.\n");
 }
index eb3d63cca1cad0aa2a82ef1368619bad2ec5ef1d..d6e4f54030b828bbb9e23645dab451fc6d9ad2ab 100644 (file)
@@ -1,5 +1,5 @@
 /* Remote debugging interface for MONITOR boot monitor, for GDB.
-   Copyright 1990, 1991, 1992 Free Software Foundation, Inc.
+   Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
    Contributed by Cygnus Support. Written by Rob Savoye for Cygnus.
 
 This file is part of GDB.
@@ -59,7 +59,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 struct monitor_ops *current_monitor;
 extern struct target_ops rom68k_ops;           /* Forward declaration */
 extern struct target_ops mon68_ops;            /* Forward declaration */
-extern struct target_ops bug_ops;              /* Forward declaration */
+static struct target_ops bug_ops;              /* Forward declaration */
 extern struct monitor_ops rom68k_cmds;         /* Forward declaration */
 extern struct monitor_ops mon68_cmds;          /* Forward declaration */
 extern struct monitor_ops bug_cmds;            /* Forward declaration */
@@ -80,10 +80,10 @@ FILE *log_file;
 
 static int timeout = 24;
 
-/* Descriptor for I/O to remote machine.  Initialize it to -1 so that
-   monitor_open knows that we don't have a file open when the program
-   starts.  */
-static serial_t monitor_desc;
+/* Descriptor for I/O to remote machine.  Initialize it to NULL so that
+   monitor_open knows that we don't have a file open when the program starts.
+   */
+static serial_t monitor_desc = NULL;
 
 /* Send data to monitor.  Works just like printf. */
 
@@ -333,7 +333,7 @@ general_open(args, name, from_tty)
 
   monitor_desc = SERIAL_OPEN(dev_name);
 
-  if (!monitor_desc)
+  if (monitor_desc == NULL)
     perror_with_name(dev_name);
 
   /* The baud rate was specified when GDB was started.  */
@@ -409,6 +409,7 @@ monitor_close (quitting)
      int quitting;
 {
   SERIAL_CLOSE(monitor_desc);
+  monitor_desc = NULL;
 
 #if defined (LOG_FILE)
   if (log_file) {
@@ -886,7 +887,7 @@ monitor_command (args, fromtty)
 #ifdef LOG_FILE
   fprintf (log_file, "\nIn command (args=%s)\n", args);
 #endif
-  if (monitor_desc < 0)
+  if (monitor_desc == NULL)
     error("monitor target not open.");
   
   if (!args)
@@ -921,7 +922,7 @@ connect_command (args, fromtty)
 
   dont_repeat();
 
-  if (monitor_desc < 0)
+  if (monitor_desc == NULL)
     error("monitor target not open.");
   
   if (args)
@@ -1091,7 +1092,7 @@ Specify the serial device it is connected to (e.g. /dev/ttya).",
   OPS_MAGIC,                   /* Always the last thing */
 };
 
-struct target_ops bug_ops = {
+static struct target_ops bug_ops = {
   "bug",
   "Motorola's BUG remote serial debug monitor",
   "Use a remote computer running Motorola's BUG debug monitor.\n\