OSDN Git Service

Initial revision
authorjsm <jsm>
Mon, 9 Aug 1999 21:33:37 +0000 (21:33 +0000)
committerjsm <jsm>
Mon, 9 Aug 1999 21:33:37 +0000 (21:33 +0000)
gdb/kod-cisco.c [new file with mode: 0644]
gdb/kod.c [new file with mode: 0644]
gdb/mcore-rom.c [new file with mode: 0644]
gdb/mcore-tdep.c [new file with mode: 0644]

diff --git a/gdb/kod-cisco.c b/gdb/kod-cisco.c
new file mode 100644 (file)
index 0000000..b33b9e5
--- /dev/null
@@ -0,0 +1,321 @@
+/* Kernel Object Display facility for Cisco
+   Copyright 1999 Free Software Foundation, Inc.
+   
+   Written by Tom Tromey <tromey@cygnus.com>.
+   
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "gdb_string.h"
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+/* Define this to turn off communication with target.  */
+/* #define FAKE_PACKET */
+
+/* Size of buffer used for remote communication.  */
+#define PBUFSIZ 400
+
+/* Pointers to gdb callbacks.  */
+static void (*gdb_kod_display) (char *);
+static void (*gdb_kod_query) (char *, char *, int *);
+
+\f
+
+/* Initialize and return library name and version.
+   The gdb side of KOD, kod.c, passes us two functions: one for
+   displaying output (presumably to the user) and the other for
+   querying the target.  */
+char *
+cisco_kod_open (char *arg,
+               void (*display_func) (char *),
+               void (*query_func) (char *, char *, int *))
+{
+  char buffer[PBUFSIZ];
+  int bufsiz = PBUFSIZ;
+  int i, count;
+
+  gdb_kod_display = display_func;
+  gdb_kod_query = query_func;
+
+  /* Get the OS info, and check the version field.  This is the stub
+     version, which we use to see whether we will understand what
+     comes back.  This is lame, but the `qKoL' request doesn't
+     actually provide enough configurability.
+     
+     Right now the only defined version number is `0.0.0'.
+     This stub supports qKoI and the `a' (any) object requests qKaL
+     and qKaI.  Each `a' object is returned as a 4-byte integer ID.
+     An info request on an object returns a pair of 4-byte integers;
+     the first is the object pointer and the second is the thread ID.  */
+
+#ifndef FAKE_PACKET
+  (*gdb_kod_query) ("oI;", buffer, &bufsiz);
+#else
+  strcpy (buffer, "Cisco IOS/Classic/13.4 0.0.0");
+#endif
+
+  count = 2;
+  for (i = 0; count && buffer[i] != '\0'; ++i)
+    {
+      if (buffer[i] == ' ')
+       --count;
+    }
+
+  if (buffer[i] == '\0')
+    error ("Remote returned malformed packet\n");
+  if (strcmp (&buffer[i], "0.0.0"))
+    error ("Remote returned unknown stub version: %s\n", &buffer[i]);
+
+  /* Return name, version, and description.  I hope we have enough
+     space.  */
+  return (strdup ("gdbkodcisco v0.0.0 - Cisco Kernel Object Display"));
+}
+
+/* Close the connection.  */
+void
+cisco_kod_close ()
+{
+}
+
+/* Print a "bad packet" message.  */
+static void
+bad_packet ()
+{
+  (*gdb_kod_display) ("Remote target returned malformed packet.\n");
+}
+
+/* Print information about currently known kernel objects.
+   We currently ignore the argument.  There is only one mode of
+   querying the Cisco kernel: we ask for a dump of everything, and
+   it returns it.  */
+void
+cisco_kod_request (char *arg, int from_tty)
+{
+  char buffer[PBUFSIZ], command[PBUFSIZ];
+  int done = 0, i;
+  int fail = 0;
+
+  char **sync_ids;
+  int sync_len = 0;
+  int sync_next = 0;
+  char *prev_id = NULL;
+
+  if (! arg || strcmp (arg, "any"))
+    {
+      /* "Top-level" command.  This is really silly, but it also seems
+        to be how KOD is defined.  */
+      /* Even sillier is the fact that this first line must start
+        with the word "List".  See kod.tcl.  */
+      (*gdb_kod_display) ("List of Cisco Kernel Objects\n");
+      (*gdb_kod_display) ("Object\tDescription\n");
+      (*gdb_kod_display) ("any\tAny and all objects\n");
+      return;
+    }
+
+  while (! done)
+    {
+      int off = 0;             /* Where we are in the string.  */
+      long count;              /* Number of objects in this packet.  */
+      int bufsiz = PBUFSIZ;
+      char *s_end;
+
+      strcpy (command, "aL");
+      if (prev_id)
+       {
+         strcat (command, ",");
+         strcat (command, prev_id);
+       }
+      strcat (command, ";");
+
+#ifndef FAKE_PACKET
+      /* We talk to the target by calling through the query function
+        passed to us when we were initialized.  */
+      (*gdb_kod_query) (command, buffer, &bufsiz);
+#else
+      /* Fake up a multi-part packet.  */
+      if (! strncmp (&command[3], "a500005a", 8))
+       strcpy (buffer, "KAL,01,1,f500005f;f500005f;");
+      else
+       strcpy (buffer, "KAL,02,0,a500005a;a500005a;de02869f;");
+#endif
+
+      /* Empty response is an error.  */
+      if (strlen (buffer) == 0)
+       {
+         (*gdb_kod_display) ("Remote target did not recognize kernel object query command.\n");
+         fail = 1;
+         break;
+       }
+
+      /* If we don't get a `K' response then the buffer holds the
+        target's error message.  */
+      if (buffer[0] != 'K')
+       {
+         (*gdb_kod_display) (buffer);
+         fail = 1;
+         break;
+       }
+
+      /* Make sure we get the response we expect.  */
+      if (strncmp (buffer, "KAL,", 4))
+       {
+         bad_packet ();
+         fail = 1;
+         break;
+       }
+      off += 4;
+
+      /* Parse out the count.  We expect to convert exactly two
+        characters followed by a comma.  */
+      count = strtol (&buffer[off], &s_end, 16);
+      if (s_end - &buffer[off] != 2 || buffer[off + 2] != ',')
+       {
+         bad_packet ();
+         fail = 1;
+         break;
+       }
+      off += 3;
+
+      /* Parse out the `done' flag.  */
+      if ((buffer[off] != '0' && buffer[off] != '1')
+         || buffer[off + 1] != ',')
+       {
+         bad_packet ();
+         fail = 1;
+         break;
+       }
+      done = buffer[off] == '1';
+      off += 2;
+
+      /* Id of the last item; we might this to construct the next
+        request.  */
+      prev_id = &buffer[off];
+      if (strlen (prev_id) < 8 || buffer[off + 8] != ';')
+       {
+         bad_packet ();
+         fail = 1;
+         break;
+       }
+      buffer[off + 8] = '\0';
+      off += 9;
+
+      if (sync_len == 0)
+       sync_ids = (char **) xmalloc (count * sizeof (char *));
+      else
+       sync_ids = (char **) xrealloc (sync_ids,
+                                      (sync_len + count) * sizeof (char *));
+      sync_len += count;
+
+      for (i = 0; i < count; ++i)
+       {
+         if (strlen (&buffer[off]) < 8 || buffer[off + 8] != ';')
+           {
+             bad_packet ();
+             fail = 1;
+             break;
+           }
+         buffer[off + 8] = '\0';
+         sync_ids[sync_next++] = xstrdup (&buffer[off]);
+         off += 9;
+       }
+
+      if (buffer[off] != '\0')
+       {
+         bad_packet ();
+         fail = 1;
+         break;
+       }
+    }
+
+  /* We've collected all the sync object IDs.  Now query to get the
+     specific information, and arrange to print this info.  */
+  if (! fail)
+    {
+      (*gdb_kod_display) ("Object ID\tObject Pointer\tThread ID\n");
+
+      for (i = 0; i < sync_next; ++i)
+       {
+         int off = 0;
+         int bufsiz = PBUFSIZ;
+
+         /* For now assume a query can be accomplished in a single
+            transaction.  This is implied in the protocol document.
+            See comments above, and the KOD protocol document, to
+            understand the parsing of the return value.  */
+         strcpy (command, "aI,");
+         strcat (command, sync_ids[i]);
+         strcat (command, ";");
+
+#ifndef FAKE_PACKET
+         (*gdb_kod_query) (command, buffer, &bufsiz);
+#else
+         strcpy (buffer, "KAI,");
+         strcat (buffer, sync_ids[i]);
+         strcat (buffer, ",ffef00a0,cd00123d;");
+#endif
+
+         if (strlen (buffer) == 0)
+           {
+             (*gdb_kod_display) ("Remote target did not recognize KOD command.\n");
+             break;
+           }
+
+         if (strncmp (buffer, "KAI,", 4))
+           {
+             bad_packet ();
+             break;
+           }
+         off += 4;
+
+         if (strncmp (&buffer[off], sync_ids[i], 8)
+             || buffer[off + 8] != ',')
+           {
+             bad_packet ();
+             break;
+           }
+         off += 9;
+
+         /* Extract thread id and sync object pointer.  */
+         if (strlen (&buffer[off]) != 2 * 8 + 2
+             || buffer[off + 8] != ','
+             || buffer[off + 17] != ';')
+           {
+             bad_packet ();
+             break;
+           }
+
+         buffer[off + 8] = '\0';
+         buffer[off + 17] = '\0';
+
+         /* Display the result.  */
+         (*gdb_kod_display) (sync_ids[i]);
+         (*gdb_kod_display) ("\t");
+         (*gdb_kod_display) (&buffer[off]);
+         (*gdb_kod_display) ("\t");
+         (*gdb_kod_display) (&buffer[off + 9]);
+         (*gdb_kod_display) ("\n");
+       }
+    }
+
+  /* Free memory.  */
+  for (i = 0; i < sync_next; ++i)
+    free (sync_ids[i]);
+  free (sync_ids);
+}
diff --git a/gdb/kod.c b/gdb/kod.c
new file mode 100644 (file)
index 0000000..a096910
--- /dev/null
+++ b/gdb/kod.c
@@ -0,0 +1,239 @@
+/* Kernel Object Display generic routines and callbacks
+   Copyright 1998, 1999 Free Software Foundation, Inc.
+
+   Written by Fernando Nasser <fnasser@cygnus.com> for Cygnus Solutions.
+
+   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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "target.h"
+#include "gdb_string.h"
+
+/* Prototypes for exported functions.  */
+void _initialize_kod (void);
+
+/* Prototypes for local functions.  */
+static void show_kod (char *, int);
+static void info_kod_command (char *, int);
+static void load_kod_library (char *);
+
+/* Prototypes for callbacks.  These are passed into the KOD modules.  */
+static void gdb_kod_display (char *);
+static void gdb_kod_query (char *, char *, int *);
+
+/* These functions are imported from the KOD module.
+   
+   gdb_kod_open - initiates the KOD connection to the remote.  The
+   first argument is the display function the module should use to
+   communicate with the user.  The second argument is the query
+   function the display should use to communicate with the target.
+   This should call error() if there is an error.  Otherwise it should
+   return a malloc()d string of the form:
+   
+   NAME VERSION - DESCRIPTION
+   
+   Neither NAME nor VERSION should contain a hyphen.
+
+   
+   gdb_kod_request - This is used when the user enters an "info
+   <module>" request.  The remaining arguments are passed as the first
+   argument.  The second argument is the standard `from_tty'
+   argument.
+
+   
+   gdb_kod_close - This is called when the KOD connection to the
+   remote should be terminated.  */
+
+static char *(*gdb_kod_open) (void *, void *);
+static void (*gdb_kod_request) (char *, int);
+static void (*gdb_kod_close) ();
+
+
+/* Name of inferior's operating system.  */
+char *operating_system;
+
+/* We save a copy of the OS so that we can properly reset when
+   switching OS's.  */
+static char *old_operating_system;
+
+/* Functions imported from the library for all supported OSes.
+   FIXME: we really should do something better, such as dynamically
+   loading the KOD modules.  */
+extern char *ecos_kod_open (void *, void *);
+extern void ecos_kod_request (char *, int);
+extern void ecos_kod_close ();
+extern char *cisco_kod_open (void *, void *);
+extern void cisco_kod_request (char *, int);
+extern void cisco_kod_close ();
+
+
+/* Print a line of data generated by the module.  */
+
+static void
+gdb_kod_display (char *arg)
+{
+  printf_filtered ("%s", arg);
+}
+
+/* Queries the target on behalf of the module.  */
+
+static void
+gdb_kod_query (char *arg, char *result, int *maxsiz)
+{
+  int bufsiz = 0;
+
+  /* Check if current target has remote_query capabilities.
+     If not, it does not have kod either.  */
+  if (! current_target.to_query)
+    {
+      strcpy (result,
+              "ERR: Kernel Object Display not supported by current target\n");
+      return;
+    }
+
+  /* Just get the maximum buffer size.  */
+  target_query ((int) 'K', 0, 0, &bufsiz);
+
+  /* Check if *we* were called just for getting the buffer size.  */
+  if (*maxsiz == 0)
+    {
+      *maxsiz = bufsiz;
+      strcpy (result, "OK");
+      return;
+    }
+
+  /* Check if caller can handle a buffer this large, if not, adjust.  */
+  if (bufsiz > *maxsiz)
+    bufsiz = *maxsiz;
+
+  /* See if buffer can hold the query (usually it can, as the query is
+     short).  */
+  if (strlen (arg) >= bufsiz)
+    error ("kod: query argument too long");
+
+  /* Send actual request.  */
+  if (target_query ((int) 'K', arg, result, &bufsiz))
+    strcpy (result, "ERR: remote query failed");
+}
+
+/* Print name of kod command after selecting the appropriate kod
+   formatting library module.  As a side effect we create a new "info"
+   subcommand which is what the user actually uses to query the OS.  */
+
+static void
+kod_set_os (char *arg, int from_tty, struct cmd_list_element *command)
+{
+  char *p;
+
+  if (command->type != set_cmd)
+    return;
+
+  /* If we had already had an open OS, close it.  */
+  if (gdb_kod_close)
+    (*gdb_kod_close) ();
+
+  /* Also remove the old OS's command.  */
+  if (old_operating_system)
+    {
+      delete_cmd (old_operating_system, &infolist);
+      free (old_operating_system);
+    }
+  old_operating_system = strdup (operating_system);
+
+  if (! operating_system || ! *operating_system)
+    {
+      /* If user set operating system to empty, we want to forget we
+        had a module open.  Setting these variables is just nice for
+        debugging and clarity.  */
+      gdb_kod_open = NULL;
+      gdb_kod_request = NULL;
+      gdb_kod_close = NULL;
+    }
+  else
+    {
+      char *kodlib;
+
+      load_kod_library (operating_system);
+
+      kodlib = (*gdb_kod_open) (gdb_kod_display, gdb_kod_query);
+
+      /* Add kod related info commands to gdb.  */
+      add_info (operating_system, info_kod_command,
+               "Displays information about Kernel Objects.");
+
+      p = strrchr (kodlib, '-');
+      if (p != NULL)
+       p++;
+      else
+       p = "Unknown KOD library";
+      printf_filtered ("%s - %s\n", operating_system, p);
+
+      free (kodlib);
+    }
+}
+
+/* Print information about currently known kernel objects of the
+   specified type or a list of all known kernel object types if
+   argument is empty.  */
+
+static void
+info_kod_command (char *arg, int from_tty)
+{
+  (*gdb_kod_request) (arg, from_tty);
+}
+
+/* Print name of kod command after selecting the appropriate kod
+   formatting library module.  */
+
+static void
+load_kod_library (char *lib)
+{
+#if 0
+  /* FIXME: Don't have the eCos code here.  */
+  if (! strcmp (lib, "ecos"))
+    {
+      gdb_kod_open = ecos_kod_open;
+      gdb_kod_request = ecos_kod_request;
+      gdb_kod_close = ecos_kod_close;
+    }
+  else
+#endif /* 0 */
+   if (! strcmp (lib, "cisco"))
+    {
+      gdb_kod_open = cisco_kod_open;
+      gdb_kod_request = cisco_kod_request;
+      gdb_kod_close = cisco_kod_close;
+    }
+  else
+    error ("Unknown operating system: %s\n", operating_system);
+}
+
+void
+_initialize_kod ()
+{
+  struct cmd_list_element *c;
+
+  c = add_set_cmd ("os", no_class, var_string,
+                  (char *) &operating_system,
+                  "Set operating system",
+                  &setlist);
+  c->function.sfunc = kod_set_os;
+  add_show_from_set (c, &showlist);
+}
diff --git a/gdb/mcore-rom.c b/gdb/mcore-rom.c
new file mode 100644 (file)
index 0000000..e28fddc
--- /dev/null
@@ -0,0 +1,206 @@
+/* Remote debugging interface to Motorola picobug monitor for gdb,
+   the GNU debugger.
+   Copyright 1999 Free Software Foundation, Inc.
+
+   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., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "gdbcore.h"
+#include "target.h"
+#include "monitor.h"
+#include "gdb_string.h"
+
+/* Functions used only in this file. */
+
+static void init_picobug_cmds (void);
+
+
+/* Functions exported from this file. */
+
+void _initialize_picobug_rom (void);
+
+void picobug_open (char *args, int from_tty);
+
+int picobug_dumpregs (void);
+
+
+static char *picobug_inits[] =
+{"\r", NULL};
+
+static struct target_ops picobug_ops;
+static struct monitor_ops picobug_cmds;
+
+/* Picobug only supports a subset of registers from MCore. In reality,
+   it doesn't support ss1, either. */
+/* *INDENT-OFF* */
+static char *picobug_regnames[] = {
+  "r0",   "r1",   "r2",   "r3",   "r4",   "r5",   "r6",   "r7",
+  "r8",   "r9",   "r10",  "r11",  "r12",  "r13",  "r14",  "r15",
+  0,      0,      0,      0,      0,      0,      0,      0,
+  0,      0,      0,      0,      0,      0,      0,      0,
+  "psr",  "vbr",  "epsr", "fpsr", "epc",  "fpc",  0,      "ss1",
+  "ss2",  "ss3",  "ss4",  0,      0,      0,      0,      0,
+  0,      0,      0,      0,      0,      0,      0,      0,
+  0,      0,      0,      0,      0,      0,      0,      0,
+  "pc" };
+/* *INDENT-ON* */
+
+
+
+void
+picobug_open (char *args, int from_tty)
+{
+  monitor_open (args, &picobug_cmds, from_tty);
+}
+/* *INDENT-OFF* */
+/* We choose to write our own dumpregs routine, since the output of
+   the register dumping is rather difficult to encapsulate in a
+   regexp:
+
+picobug> rd                                                                 
+     pc 2f00031e      epc 2f00031e      fpc 00000000
+    psr 80000101     epsr 80000101     fpsr 00000000
+ss0-ss4 bad0beef 00000000 00000000 00000000 00000000      vbr 30005c00
+  r0-r7 2f0fff4c 00000090 00000001 00000002 00000003 00000004 00000005 00000006
+ r8-r15 2f0fff64 00000000 00000000 00000000 00000000 00000000 00000000 2f00031e */
+/* *INDENT-ON* */
+
+
+
+int
+picobug_dumpregs ()
+{
+  char buf[1024];
+  int resp_len;
+  char *p;
+
+  /* Send the dump register command to the monitor and
+     get the reply. */
+  monitor_printf (picobug_cmds.dump_registers);
+  resp_len = monitor_expect_prompt (buf, sizeof (buf));
+
+  p = strtok (buf, " \t\r\n");
+  while (p)
+    {
+      if (strchr (p, '-'))
+       {
+         /* got a range. either r0-r7, r8-r15 or ss0-ss4 */
+         if (STREQN (p, "r0", 2) || STREQN (p, "r8", 2))
+           {
+             int rn = (p[1] == '0' ? 0 : 8);
+             int i = 0;
+
+             /* Get the next 8 values and record them. */
+             while (i < 8)
+               {
+                 p = strtok (NULL, " \t\r\n");
+                 if (p)
+                   monitor_supply_register (rn + i, p);
+                 i++;
+               }
+           }
+         else if (STREQN (p, "ss", 2))
+           {
+             /* get the next five values, ignoring the first */
+             int rn;
+             p = strtok (NULL, " \t\r\n");
+             for (rn = 39; rn < 43; rn++)
+               {
+                 p = strtok (NULL, " \t\r\n");
+                 if (p)
+                   monitor_supply_register (rn, p);
+               }
+           }
+         else
+           {
+             break;
+           }
+       }
+      else
+       {
+         /* Simple register type, paired */
+         char *name = p;
+         int i;
+
+         /* Get and record value */
+         p = strtok (NULL, " \t\r\n");
+         if (p)
+           {
+             for (i = 0; i < NUM_REGS; i++)
+               {
+                 if (picobug_regnames[i] && STREQ (picobug_regnames[i], name))
+                   break;
+               }
+
+             if (i <= NUM_REGS)
+               monitor_supply_register (i, p);
+           }
+       }
+      p = strtok (NULL, " \t\r\n");
+    }
+
+  return 0;
+}
+
+static void
+init_picobug_cmds (void)
+{
+  picobug_cmds.flags = MO_GETMEM_NEEDS_RANGE | MO_CLR_BREAK_USES_ADDR | MO_PRINT_PROGRAM_OUTPUT;
+
+  picobug_cmds.init = picobug_inits;   /* Init strings                       */
+  picobug_cmds.cont = "g\n";   /* continue command                   */
+  picobug_cmds.step = "s\n";   /* single step                        */
+  picobug_cmds.set_break = "br %x\n";  /* set a breakpoint                   */
+  picobug_cmds.clr_break = "nobr %x\n";                /* clear a breakpoint                 */
+  picobug_cmds.clr_all_break = "nobr\n";       /* clear all breakpoints              */
+  picobug_cmds.setmem.cmdb = "mm %x %x ;b\n";  /* setmem.cmdb (addr, value)          */
+  picobug_cmds.setmem.cmdw = "mm %x %x ;h\n";  /* setmem.cmdw (addr, value)          */
+  picobug_cmds.setmem.cmdl = "mm %x %x ;w\n";  /* setmem.cmdl (addr, value)          */
+  picobug_cmds.getmem.cmdb = "md %x %x\n";     /* getmem.cmdb (start addr, end addr) */
+  picobug_cmds.getmem.resp_delim = ":";                /* getmem.resp_delim                  */
+  picobug_cmds.setreg.cmd = "rm %s %x\n";      /* setreg.cmd (name, value)           */
+  picobug_cmds.getreg.cmd = "rd %s\n"; /* getreg.cmd (name)                  */
+  picobug_cmds.getreg.resp_delim = ":";                /* getreg.resp_delim                  */
+  picobug_cmds.dump_registers = "rd\n";                /* dump_registers                     */
+  picobug_cmds.dumpregs = picobug_dumpregs;    /* dump registers parser              */
+  picobug_cmds.load = "lo\n";  /* download command                   */
+  picobug_cmds.prompt = "picobug> ";   /* monitor command prompt             */
+  picobug_cmds.line_term = "\n";       /* end-of-line terminator             */
+  picobug_cmds.target = &picobug_ops;  /* target operations                  */
+  picobug_cmds.stopbits = SERIAL_1_STOPBITS;   /* number of stop bits                */
+  picobug_cmds.regnames = picobug_regnames;    /* registers names                    */
+  picobug_cmds.num_breakpoints = 20;   /* number of breakpoints              */
+  picobug_cmds.magic = MONITOR_OPS_MAGIC;      /* magic                              */
+}
+
+void
+_initialize_picobug_rom ()
+{
+  int i;
+
+  /* Initialize m32r RevC monitor target */
+  init_picobug_cmds ();
+  init_monitor_ops (&picobug_ops);
+  picobug_ops.to_shortname = "picobug";
+  picobug_ops.to_longname = "picobug monitor";
+  picobug_ops.to_doc = "Debug via the picobug monitor.\n\
+Specify the serial device it is connected to (e.g. /dev/ttya).";
+  picobug_ops.to_open = picobug_open;
+
+  add_target (&picobug_ops);
+}
diff --git a/gdb/mcore-tdep.c b/gdb/mcore-tdep.c
new file mode 100644 (file)
index 0000000..1fc6e90
--- /dev/null
@@ -0,0 +1,992 @@
+/* Target-machine dependent code for Motorola MCore for GDB, the GNU debugger
+   Copyright (C) 1999 Free Software Foundation, Inc.
+
+   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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "frame.h"
+#include "symtab.h"
+#include "value.h"
+#include "gdbcmd.h"
+
+/* Functions declared and used only in this file */
+
+static CORE_ADDR mcore_analyze_prologue (struct frame_info *fi, CORE_ADDR pc, int skip_prologue);
+
+static struct frame_info *analyze_dummy_frame (CORE_ADDR pc, CORE_ADDR frame);
+
+static int get_insn (CORE_ADDR pc);
+
+/* Functions exported from this file */
+
+int mcore_use_struct_convention (int gcc_p, struct type *type);
+
+void _initialize_mcore (void);
+
+void mcore_init_extra_frame_info (struct frame_info *fi);
+
+CORE_ADDR mcore_frame_saved_pc (struct frame_info *fi);
+
+CORE_ADDR mcore_find_callers_reg (struct frame_info *fi, int regnum);
+
+CORE_ADDR mcore_frame_args_address (struct frame_info *fi);
+
+CORE_ADDR mcore_frame_locals_address (struct frame_info *fi);
+
+void mcore_virtual_frame_pointer (CORE_ADDR pc, long *reg, long *offset);
+
+CORE_ADDR mcore_push_return_address (CORE_ADDR pc, CORE_ADDR sp);
+
+CORE_ADDR mcore_push_arguments (int nargs, value_ptr * args, CORE_ADDR sp,
+                       unsigned char struct_return, CORE_ADDR struct_addr);
+
+void mcore_pop_frame (struct frame_info *fi);
+
+CORE_ADDR mcore_skip_prologue (CORE_ADDR pc);
+
+CORE_ADDR mcore_frame_chain (struct frame_info *fi);
+
+unsigned char *mcore_breakpoint_from_pc (CORE_ADDR * bp_addr, int *bp_size);
+
+int mcore_use_struct_convention (int gcc_p, struct type *type);
+
+void mcore_store_return_value (struct type *type, char *valbuf);
+
+CORE_ADDR mcore_extract_struct_value_address (char *regbuf);
+
+void mcore_extract_return_value (struct type *type, char *regbuf, char *valbuf);
+
+#ifdef MCORE_DEBUG
+int mcore_debug = 0;
+#endif
+
+/* The registers of the Motorola MCore processors */
+/* *INDENT-OFF* */
+char *mcore_register_names[] =
+{ "r0",   "r1",  "r2",    "r3",   "r4",   "r5",   "r6",   "r7",
+  "r8",   "r9",  "r10",   "r11",  "r12",  "r13",  "r14",  "r15",
+  "ar0",  "ar1", "ar2",   "ar3",  "ar4",  "ar5",  "ar6",  "ar7",
+  "ar8",  "ar9", "ar10", "ar11",  "ar12", "ar13", "ar14", "ar15",
+  "psr",  "vbr", "epsr",  "fpsr", "epc",  "fpc",  "ss0",  "ss1",
+  "ss2",  "ss3", "ss4",   "gcr",  "gsr",  "cr13", "cr14", "cr15",
+  "cr16", "cr17", "cr18", "cr19", "cr20", "cr21", "cr22", "cr23",
+  "cr24", "cr25", "cr26", "cr27", "cr28", "cr29", "cr30", "cr31",
+  "pc" };
+/* *INDENT-ON* */
+
+
+
+/* Additional info that we use for managing frames */
+struct frame_extra_info
+  {
+    /* A generic status word */
+    int status;
+
+    /* Size of this frame */
+    int framesize;
+
+    /* The register that is acting as a frame pointer, if
+       it is being used.  This is undefined if status
+       does not contain the flag MY_FRAME_IN_FP. */
+    int fp_regnum;
+  };
+
+/* frame_extra_info status flags */
+
+/* The base of the current frame is actually in the stack pointer.
+   This happens when there is no frame pointer (MCore ABI does not
+   require a frame pointer) or when we're stopped in the prologue or
+   epilogue itself.  In these cases, mcore_analyze_prologue will need
+   to update fi->frame before returning or analyzing the register
+   save instructions. */
+#define MY_FRAME_IN_SP 0x1
+
+/* The base of the current frame is in a frame pointer register.
+   This register is noted in frame_extra_info->fp_regnum.
+
+   Note that the existance of an FP might also indicate that the
+   function has called alloca. */
+#define MY_FRAME_IN_FP 0x2
+
+/* This flag is set to indicate that this frame is the top-most
+   frame. This tells frame chain not to bother trying to unwind
+   beyond this frame. */
+#define NO_MORE_FRAMES 0x4
+
+/* Instruction macros used for analyzing the prologue */
+#define IS_SUBI0(x)   (((x) & 0xfe0f) == 0x2400)       /* subi r0,oimm5    */
+#define IS_STM(x)     (((x) & 0xfff0) == 0x0070)       /* stm rf-r15,r0    */
+#define IS_STWx0(x)   (((x) & 0xf00f) == 0x9000)       /* stw rz,(r0,disp) */
+#define IS_STWxy(x)   (((x) & 0xf000) == 0x9000)       /* stw rx,(ry,disp) */
+#define IS_MOVx0(x)   (((x) & 0xfff0) == 0x1200)       /* mov rn,r0        */
+#define IS_LRW1(x)    (((x) & 0xff00) == 0x7100)       /* lrw r1,literal   */
+#define IS_MOVI1(x)   (((x) & 0xf80f) == 0x6001)       /* movi r1,imm7     */
+#define IS_BGENI1(x)  (((x) & 0xfe0f) == 0x3201)       /* bgeni r1,imm5    */
+#define IS_BMASKI1(x) (((x) & 0xfe0f) == 0x2C01)       /* bmaski r1,imm5   */
+#define IS_ADDI1(x)   (((x) & 0xfe0f) == 0x2001)       /* addi r1,oimm5    */
+#define IS_SUBI1(x)   (((x) & 0xfe0f) == 0x2401)       /* subi r1,oimm5    */
+#define IS_RSUBI1(x)  (((x) & 0xfe0f) == 0x2801)       /* rsubi r1,imm5    */
+#define IS_NOT1(x)    (((x) & 0xffff) == 0x01f1)       /* not r1           */
+#define IS_ROTLI1(x)  (((x) & 0xfe0f) == 0x3801)       /* rotli r1,imm5    */
+#define IS_BSETI1(x)  (((x) & 0xfe0f) == 0x3401)       /* bseti r1,imm5    */
+#define IS_BCLRI1(x)  (((x) & 0xfe0f) == 0x3001)       /* bclri r1,imm5    */
+#define IS_IXH1(x)    (((x) & 0xffff) == 0x1d11)       /* ixh r1,r1        */
+#define IS_IXW1(x)    (((x) & 0xffff) == 0x1511)       /* ixw r1,r1        */
+#define IS_SUB01(x)   (((x) & 0xffff) == 0x0510)       /* subu r0,r1       */
+#define IS_RTS(x)     (((x) & 0xffff) == 0x00cf)       /* jmp r15          */
+
+#define IS_R1_ADJUSTER(x) \
+    (IS_ADDI1(x) || IS_SUBI1(x) || IS_ROTLI1(x) || IS_BSETI1(x) \
+     || IS_BCLRI1(x) || IS_RSUBI1(x) || IS_NOT1(x) \
+     || IS_IXH1(x) || IS_IXW1(x))
+\f
+
+#ifdef MCORE_DEBUG
+static void
+mcore_dump_insn (char *commnt, CORE_ADDR pc, int insn)
+{
+  if (mcore_debug)
+    {
+      printf_filtered ("MCORE:  %s %08x %08x ",
+                      commnt, (unsigned int) pc, (unsigned int) insn);
+      (*tm_print_insn) (pc, &tm_print_insn_info);
+      printf_filtered ("\n");
+    }
+}
+#define mcore_insn_debug(args) { if (mcore_debug) printf_filtered args; }
+#else /* !MCORE_DEBUG */
+#define mcore_dump_insn(a,b,c) {}
+#define mcore_insn_debug(args) {}
+#endif
+
+/* Given the address at which to insert a breakpoint (BP_ADDR),
+   what will that breakpoint be?
+
+   For MCore, we have a breakpoint instruction. Since all MCore
+   instructions are 16 bits, this is all we need, regardless of
+   address. bpkt = 0x0000 */
+
+unsigned char *
+mcore_breakpoint_from_pc (CORE_ADDR * bp_addr, int *bp_size)
+{
+  static char breakpoint[] =
+  {0x00, 0x00};
+  *bp_size = 2;
+  return breakpoint;
+}
+
+/* Helper function for several routines below.  This funtion simply
+   sets up a fake, aka dummy, frame (not a _call_ dummy frame) that
+   we can analyze with mcore_analyze_prologue. */
+
+static struct frame_info *
+analyze_dummy_frame (CORE_ADDR pc, CORE_ADDR frame)
+{
+  static struct frame_info *dummy = NULL;
+
+  if (dummy == NULL)
+    {
+      dummy = (struct frame_info *) xmalloc (sizeof (struct frame_info));
+      dummy->saved_regs = (CORE_ADDR *) xmalloc (SIZEOF_FRAME_SAVED_REGS);
+      dummy->extra_info =
+       (struct frame_extra_info *) xmalloc (sizeof (struct frame_extra_info));
+    }
+
+  dummy->next = NULL;
+  dummy->prev = NULL;
+  dummy->pc = pc;
+  dummy->frame = frame;
+  dummy->extra_info->status = 0;
+  dummy->extra_info->framesize = 0;
+  memset (dummy->saved_regs, '\000', SIZEOF_FRAME_SAVED_REGS);
+  mcore_analyze_prologue (dummy, 0, 0);
+  return dummy;
+}
+
+/* Function prologues on the Motorol MCore processors consist of:
+
+   - adjustments to the stack pointer (r1 used as scratch register)
+   - store word/multiples that use r0 as the base address
+   - making a copy of r0 into another register (a "frame" pointer)
+
+   Note that the MCore really doesn't have a real frame pointer.
+   Instead, the compiler may copy the SP into a register (usually
+   r8) to act as an arg pointer.  For our target-dependent purposes,
+   the frame info's "frame" member will be the beginning of the
+   frame. The SP could, in fact, point below this.
+
+   The prologue ends when an instruction fails to meet either of
+   the first two criteria or when an FP is made.  We make a special
+   exception for gcc. When compiling unoptimized code, gcc will
+   setup stack slots. We need to make sure that we skip the filling
+   of these stack slots as much as possible. This is only done
+   when SKIP_PROLOGUE is set, so that it does not mess up
+   backtraces. */
+
+/* Analyze the prologue of frame FI to determine where registers are saved,
+   the end of the prologue, etc. Return the address of the first line
+   of "real" code (i.e., the end of the prologue). */
+
+static CORE_ADDR
+mcore_analyze_prologue (struct frame_info *fi, CORE_ADDR pc, int skip_prologue)
+{
+  CORE_ADDR func_addr, func_end, addr, stop;
+  CORE_ADDR stack_size;
+  int insn, rn;
+  int status, fp_regnum, flags;
+  int framesize;
+  int register_offsets[NUM_REGS];
+  char *name;
+
+  /* If provided, use the PC in the frame to look up the
+     start of this function. */
+  pc = (fi == NULL ? pc : fi->pc);
+
+  /* Find the start of this function. */
+  status = find_pc_partial_function (pc, &name, &func_addr, &func_end);
+
+  /* If the start of this function could not be found or if the debbuger
+     is stopped at the first instruction of the prologue, do nothing. */
+  if (status == 0)
+    return pc;
+
+  /* If the debugger is entry function, give up. */
+  if (func_addr == entry_point_address ())
+    {
+      if (fi != NULL)
+       fi->extra_info->status |= NO_MORE_FRAMES;
+      return pc;
+    }
+
+  /* At the start of a function, our frame is in the stack pointer. */
+  flags = MY_FRAME_IN_SP;
+
+  /* Start decoding the prologue.  We start by checking two special cases:
+
+     1. We're about to return
+     2. We're at the first insn of the prologue.
+
+     If we're about to return, our frame has already been deallocated.
+     If we are stopped at the first instruction of a prologue,
+     then our frame has not yet been set up. */
+
+  /* Get the first insn from memory (all MCore instructions are 16 bits) */
+  mcore_insn_debug (("MCORE: starting prologue decoding\n"));
+  insn = get_insn (pc);
+  mcore_dump_insn ("got 1: ", pc, insn);
+
+  /* Check for return. */
+  if (fi != NULL && IS_RTS (insn))
+    {
+      mcore_insn_debug (("MCORE: got jmp r15"));
+      if (fi->next == NULL)
+       fi->frame = read_sp ();
+      return fi->pc;
+    }
+
+  /* Check for first insn of prologue */
+  if (fi != NULL && fi->pc == func_addr)
+    {
+      if (fi->next == NULL)
+       fi->frame = read_sp ();
+      return fi->pc;
+    }
+
+  /* Figure out where to stop scanning */
+  stop = (fi ? fi->pc : func_end);
+
+  /* Don't walk off the end of the function */
+  stop = (stop > func_end ? func_end : stop);
+
+  /* REGISTER_OFFSETS will contain offsets, from the top of the frame
+     (NOT the frame pointer), for the various saved registers or -1
+     if the register is not saved. */
+  for (rn = 0; rn < NUM_REGS; rn++)
+    register_offsets[rn] = -1;
+
+  /* Analyze the prologue. Things we determine from analyzing the
+     prologue include:
+     * the size of the frame
+     * where saved registers are located (and which are saved)
+     * FP used? */
+  mcore_insn_debug (("MCORE: Scanning prologue: func_addr=0x%x, stop=0x%x\n",
+                    (unsigned int) func_addr, (unsigned int) stop));
+
+  framesize = 0;
+  for (addr = func_addr; addr < stop; addr += 2)
+    {
+      /* Get next insn */
+      insn = get_insn (addr);
+      mcore_dump_insn ("got 2: ", addr, insn);
+
+      if (IS_SUBI0 (insn))
+       {
+         int offset = 1 + ((insn >> 4) & 0x1f);
+         mcore_insn_debug (("MCORE: got subi r0,%d; contnuing\n", offset));
+         framesize += offset;
+         continue;
+       }
+      else if (IS_STM (insn))
+       {
+         /* Spill register(s) */
+         int offset;
+         int start_register;
+
+         /* BIG WARNING! The MCore ABI does not restrict functions
+            to taking only one stack allocation. Therefore, when
+            we save a register, we record the offset of where it was
+            saved relative to the current framesize. This will
+            then give an offset from the SP upon entry to our
+            function. Remember, framesize is NOT constant until
+            we're done scanning the prologue. */
+         start_register = (insn & 0xf);
+         mcore_insn_debug (("MCORE: got stm r%d-r15,(r0)\n", start_register));
+
+         for (rn = start_register, offset = 0; rn <= 15; rn++, offset += 4)
+           {
+             register_offsets[rn] = framesize - offset;
+             mcore_insn_debug (("MCORE: r%d saved at 0x%x (offset %d)\n", rn,
+                                register_offsets[rn], offset));
+           }
+         mcore_insn_debug (("MCORE: continuing\n"));
+         continue;
+       }
+      else if (IS_STWx0 (insn))
+       {
+         /* Spill register: see note for IS_STM above. */
+         int imm;
+
+         rn = (insn >> 8) & 0xf;
+         imm = (insn >> 4) & 0xf;
+         register_offsets[rn] = framesize - (imm << 2);
+         mcore_insn_debug (("MCORE: r%d saved at offset 0x%x\n", rn, register_offsets[rn]));
+         mcore_insn_debug (("MCORE: continuing\n"));
+         continue;
+       }
+      else if (IS_MOVx0 (insn))
+       {
+         /* We have a frame pointer, so this prologue is over.  Note
+            the register which is acting as the frame pointer. */
+         flags |= MY_FRAME_IN_FP;
+         flags &= ~MY_FRAME_IN_SP;
+         fp_regnum = insn & 0xf;
+         mcore_insn_debug (("MCORE: Found a frame pointer: r%d\n", fp_regnum));
+
+         /* If we found an FP, we're at the end of the prologue. */
+         mcore_insn_debug (("MCORE: end of prologue\n"));
+         if (skip_prologue)
+           continue;
+
+         /* If we're decoding prologue, stop here. */
+         addr += 2;
+         break;
+       }
+      else if (IS_STWxy (insn) && (flags & MY_FRAME_IN_FP) && ((insn & 0xf) == fp_regnum))
+       {
+         /* Special case. Skip over stack slot allocs, too. */
+         mcore_insn_debug (("MCORE: push arg onto stack.\n"));
+         continue;
+       }
+      else if (IS_LRW1 (insn) || IS_MOVI1 (insn)
+              || IS_BGENI1 (insn) || IS_BMASKI1 (insn))
+       {
+         int adjust = 0;
+         int offset = 0;
+         int insn2;
+
+         mcore_insn_debug (("MCORE: looking at large frame\n"));
+         if (IS_LRW1 (insn))
+           {
+             adjust =
+               read_memory_integer ((addr + 2 + ((insn & 0xff) << 2)) & 0xfffffffc, 4);
+           }
+         else if (IS_MOVI1 (insn))
+           adjust = (insn >> 4) & 0x7f;
+         else if (IS_BGENI1 (insn))
+           adjust = 1 << ((insn >> 4) & 0x1f);
+         else                  /* IS_BMASKI (insn) */
+           adjust = (1 << (adjust >> 4) & 0x1f) - 1;
+
+         mcore_insn_debug (("MCORE: base framesize=0x%x\n", adjust));
+
+         /* May have zero or more insns which modify r1 */
+         mcore_insn_debug (("MCORE: looking for r1 adjusters...\n"));
+         offset = 2;
+         insn2 = get_insn (addr + offset);
+         while (IS_R1_ADJUSTER (insn2))
+           {
+             int imm;
+
+             imm = (insn2 >> 4) & 0x1f;
+             mcore_dump_insn ("got 3: ", addr + offset, insn);
+             if (IS_ADDI1 (insn2))
+               {
+                 adjust += (imm + 1);
+                 mcore_insn_debug (("MCORE: addi r1,%d\n", imm + 1));
+               }
+             else if (IS_SUBI1 (insn2))
+               {
+                 adjust -= (imm + 1);
+                 mcore_insn_debug (("MCORE: subi r1,%d\n", imm + 1));
+               }
+             else if (IS_RSUBI1 (insn2))
+               {
+                 adjust = imm - adjust;
+                 mcore_insn_debug (("MCORE: rsubi r1,%d\n", imm + 1));
+               }
+             else if (IS_NOT1 (insn2))
+               {
+                 adjust = ~adjust;
+                 mcore_insn_debug (("MCORE: not r1\n"));
+               }
+             else if (IS_ROTLI1 (insn2))
+               {
+                 adjust <<= imm;
+                 mcore_insn_debug (("MCORE: rotli r1,%d\n", imm + 1));
+               }
+             else if (IS_BSETI1 (insn2))
+               {
+                 adjust |= (1 << imm);
+                 mcore_insn_debug (("MCORE: bseti r1,%d\n", imm));
+               }
+             else if (IS_BCLRI1 (insn2))
+               {
+                 adjust &= ~(1 << imm);
+                 mcore_insn_debug (("MCORE: bclri r1,%d\n", imm));
+               }
+             else if (IS_IXH1 (insn2))
+               {
+                 adjust *= 3;
+                 mcore_insn_debug (("MCORE: ix.h r1,r1\n"));
+               }
+             else if (IS_IXW1 (insn2))
+               {
+                 adjust *= 5;
+                 mcore_insn_debug (("MCORE: ix.w r1,r1\n"));
+               }
+
+             offset += 2;
+             insn2 = get_insn (addr + offset);
+           };
+
+         mcore_insn_debug (("MCORE: done looking for r1 adjusters\n"));
+
+         /* If the next insn adjusts the stack pointer, we keep everything;
+            if not, we scrap it and we've found the end of the prologue. */
+         if (IS_SUB01 (insn2))
+           {
+             addr += offset;
+             framesize += adjust;
+             mcore_insn_debug (("MCORE: found stack adjustment of 0x%x bytes.\n", adjust));
+             mcore_insn_debug (("MCORE: skipping to new address 0x%x\n", addr));
+             mcore_insn_debug (("MCORE: continuing\n"));
+             continue;
+           }
+
+         /* None of these instructions are prologue, so don't touch
+            anything. */
+         mcore_insn_debug (("MCORE: no subu r1,r0, NOT altering framesize.\n"));
+         break;
+       }
+
+      /* This is not a prologue insn, so stop here. */
+      mcore_insn_debug (("MCORE: insn is not a prologue insn -- ending scan\n"));
+      break;
+    }
+
+  mcore_insn_debug (("MCORE: done analyzing prologue\n"));
+  mcore_insn_debug (("MCORE: prologue end = 0x%x\n", addr));
+
+  /* Save everything we have learned about this frame into FI. */
+  if (fi != NULL)
+    {
+      fi->extra_info->framesize = framesize;
+      fi->extra_info->fp_regnum = fp_regnum;
+      fi->extra_info->status = flags;
+
+      /* Fix the frame pointer. When gcc uses r8 as a frame pointer,
+         it is really an arg ptr. We adjust fi->frame to be a "real"
+         frame pointer. */
+      if (fi->next == NULL)
+       {
+         if (fi->extra_info->status & MY_FRAME_IN_SP)
+           fi->frame = read_sp () + framesize;
+         else
+           fi->frame = read_register (fp_regnum) + framesize;
+       }
+
+      /* Note where saved registers are stored. The offsets in REGISTER_OFFSETS
+         are computed relative to the top of the frame. */
+      for (rn = 0; rn < NUM_REGS; rn++)
+       {
+         if (register_offsets[rn] >= 0)
+           {
+             fi->saved_regs[rn] = fi->frame - register_offsets[rn];
+             mcore_insn_debug (("Saved register %s stored at 0x%08x, value=0x%08x\n",
+                              mcore_register_names[rn], fi->saved_regs[rn],
+                             read_memory_integer (fi->saved_regs[rn], 4)));
+           }
+       }
+    }
+
+  /* Return addr of first non-prologue insn. */
+  return addr;
+}
+
+/* Given a GDB frame, determine the address of the calling function's frame.
+   This will be used to create a new GDB frame struct, and then
+   INIT_EXTRA_FRAME_INFO and INIT_FRAME_PC will be called for the new frame. */
+
+CORE_ADDR
+mcore_frame_chain (struct frame_info * fi)
+{
+  struct frame_info *dummy;
+  CORE_ADDR callers_addr;
+
+  /* Analyze the prologue of this function. */
+  if (fi->extra_info->status == 0)
+    mcore_analyze_prologue (fi, 0, 0);
+
+  /* If mcore_analyze_prologue set NO_MORE_FRAMES, quit now. */
+  if (fi->extra_info->status & NO_MORE_FRAMES)
+    return 0;
+
+  /* Now that we've analyzed our prologue, we can start to ask
+     for information about our caller. The easiest way to do
+     this is to analyze our caller's prologue. 
+
+     If our caller has a frame pointer, then we need to find
+     the value of that register upon entry to our frame.
+     This value is either in fi->saved_regs[rn] if it's saved,
+     or it's still in a register.
+
+     If our caller does not have a frame pointer, then his frame base
+     is <our base> + -<caller's frame size>. */
+  dummy = analyze_dummy_frame (FRAME_SAVED_PC (fi), fi->frame);
+
+  if (dummy->extra_info->status & MY_FRAME_IN_FP)
+    {
+      int fp = dummy->extra_info->fp_regnum;
+
+      /* Our caller has a frame pointer. */
+      if (fi->saved_regs[fp] != 0)
+       {
+         /* The "FP" was saved on the stack.  Don't forget to adjust
+            the "FP" with the framesize to get a real FP. */
+         callers_addr = read_memory_integer (fi->saved_regs[fp], REGISTER_SIZE)
+           + dummy->extra_info->framesize;
+       }
+      else
+       {
+         /* It's still in the register.  Don't forget to adjust
+            the "FP" with the framesize to get a real FP. */
+         callers_addr = read_register (fp) + dummy->extra_info->framesize;
+       }
+    }
+  else
+    {
+      /* Our caller does not have a frame pointer. */
+      callers_addr = fi->frame + dummy->extra_info->framesize;
+    }
+
+  return callers_addr;
+}
+
+/* Skip the prologue of the function at PC. */
+
+CORE_ADDR
+mcore_skip_prologue (CORE_ADDR pc)
+{
+  CORE_ADDR func_addr, func_end;
+  struct symtab_and_line sal;
+
+  /* If we have line debugging information, then the end of the
+     prologue should the first assembly instruction of  the first
+     source line */
+  if (find_pc_partial_function (pc, NULL, &func_addr, &func_end))
+    {
+      sal = find_pc_line (func_addr, 0);
+      if (sal.end && sal.end < func_end)
+       return sal.end;
+    }
+
+  return mcore_analyze_prologue (NULL, pc, 1);
+}
+
+/* Return the address at which function arguments are offset. */
+CORE_ADDR
+mcore_frame_args_address (struct frame_info * fi)
+{
+  return fi->frame - fi->extra_info->framesize;
+}
+
+CORE_ADDR
+mcore_frame_locals_address (struct frame_info * fi)
+{
+  return fi->frame - fi->extra_info->framesize;
+}
+
+/* Return the frame pointer in use at address PC. */
+
+void
+mcore_virtual_frame_pointer (CORE_ADDR pc, long *reg, long *offset)
+{
+  struct frame_info *dummy = analyze_dummy_frame (pc, 0);
+  if (dummy->extra_info->status & MY_FRAME_IN_SP)
+    {
+      *reg = SP_REGNUM;
+      *offset = 0;
+    }
+  else
+    {
+      *reg = dummy->extra_info->fp_regnum;
+      *offset = 0;
+    }
+}
+
+/* Find the value of register REGNUM in frame FI. */
+
+CORE_ADDR
+mcore_find_callers_reg (struct frame_info *fi, int regnum)
+{
+  for (; fi != NULL; fi = fi->next)
+    {
+      if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
+       return generic_read_register_dummy (fi->pc, fi->frame, regnum);
+      else if (fi->saved_regs[regnum] != 0)
+       return read_memory_integer (fi->saved_regs[regnum],
+                                   REGISTER_SIZE);
+    }
+
+  return read_register (regnum);
+}
+
+/* Find the saved pc in frame FI. */
+
+CORE_ADDR
+mcore_frame_saved_pc (struct frame_info * fi)
+{
+
+  if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
+    return generic_read_register_dummy (fi->pc, fi->frame, PC_REGNUM);
+  else
+    return mcore_find_callers_reg (fi, PR_REGNUM);
+}
+\f
+/* INFERIOR FUNCTION CALLS */
+
+/* This routine gets called when either the user uses the "return"
+   command, or the call dummy breakpoint gets hit. */
+
+void
+mcore_pop_frame (struct frame_info *fi)
+{
+  int rn;
+
+  if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
+    generic_pop_dummy_frame ();
+  else
+    {
+      /* Write out the PC we saved. */
+      write_register (PC_REGNUM, FRAME_SAVED_PC (fi));
+
+      /* Restore any saved registers. */
+      for (rn = 0; rn < NUM_REGS; rn++)
+       {
+         if (fi->saved_regs[rn] != 0)
+           {
+             ULONGEST value;
+
+             value = read_memory_unsigned_integer (fi->saved_regs[rn],
+                                                   REGISTER_SIZE);
+             write_register (rn, value);
+           }
+       }
+
+      /* Actually cut back the stack. */
+      write_register (SP_REGNUM, FRAME_FP (fi));
+    }
+
+  /* Finally, throw away any cached frame information. */
+  flush_cached_frames ();
+}
+
+/* Setup arguments and PR for a call to the target. First six arguments
+   go in FIRST_ARGREG -> LAST_ARGREG, subsequent args go on to the stack.
+
+   * Types with lengths greater than REGISTER_SIZE may not be split
+   between registers and the stack, and they must start in an even-numbered
+   register. Subsequent args will go onto the stack.
+
+   * Structs may be split between registers and stack, left-aligned.
+
+   * If the function returns a struct which will not fit into registers (it's
+   more than eight bytes), we must allocate for that, too. Gdb will tell
+   us where this buffer is (STRUCT_ADDR), and we simply place it into
+   FIRST_ARGREG, since the MCORE treats struct returns (of less than eight
+   bytes) as hidden first arguments. */
+
+CORE_ADDR
+mcore_push_arguments (int nargs, value_ptr * args, CORE_ADDR sp,
+                     unsigned char struct_return, CORE_ADDR struct_addr)
+{
+  int argreg;
+  int argnum;
+  struct stack_arg
+    {
+      int len;
+      char *val;
+    }
+   *stack_args;
+  int nstack_args = 0;
+
+  stack_args = (struct stack_arg *) alloca (nargs * sizeof (struct stack_arg));
+
+  argreg = FIRST_ARGREG;
+
+  /* Align the stack. This is mostly a nop, but not always. It will be needed
+     if we call a function which has argument overflow. */
+  sp &= ~3;
+
+  /* If this function returns a struct which does not fit in the
+     return registers, we must pass a buffer to the function
+     which it can use to save the return value. */
+  if (struct_return)
+    write_register (argreg++, struct_addr);
+
+  /* FIXME: what about unions? */
+  for (argnum = 0; argnum < nargs; argnum++)
+    {
+      char *val = (char *) VALUE_CONTENTS (args[argnum]);
+      int len = TYPE_LENGTH (VALUE_TYPE (args[argnum]));
+      struct type *type = VALUE_TYPE (args[argnum]);
+      int olen;
+
+      mcore_insn_debug (("MCORE PUSH: argreg=%d; len=%d; %s\n",
+                        argreg, len, TYPE_CODE (type) == TYPE_CODE_STRUCT ? "struct" : "not struct"));
+      /* Arguments larger than a register must start in an even
+         numbered register. */
+      olen = len;
+
+      if (TYPE_CODE (type) != TYPE_CODE_STRUCT && len > REGISTER_SIZE && argreg % 2)
+       {
+         mcore_insn_debug (("MCORE PUSH: %d > REGISTER_SIZE: and %s is not even\n",
+                            len, mcore_register_names[argreg]));
+         argreg++;
+       }
+
+      if ((argreg <= LAST_ARGREG && len <= (LAST_ARGREG - argreg + 1) * REGISTER_SIZE)
+         || (TYPE_CODE (type) == TYPE_CODE_STRUCT))
+       {
+         /* Something that will fit entirely into registers (or a struct
+            which may be split between registers and stack). */
+         mcore_insn_debug (("MCORE PUSH: arg %d going into regs\n", argnum));
+
+         if (TYPE_CODE (type) == TYPE_CODE_STRUCT && olen < REGISTER_SIZE)
+           {
+             /* Small structs must be right aligned within the register,
+                the most significant bits are undefined. */
+             write_register (argreg, extract_unsigned_integer (val, len));
+             argreg++;
+             len = 0;
+           }
+
+         while (len > 0 && argreg <= LAST_ARGREG)
+           {
+             write_register (argreg, extract_unsigned_integer (val, REGISTER_SIZE));
+             argreg++;
+             val += REGISTER_SIZE;
+             len -= REGISTER_SIZE;
+           }
+
+         /* Any remainder for the stack is noted below... */
+       }
+      else if (TYPE_CODE (VALUE_TYPE (args[argnum])) != TYPE_CODE_STRUCT
+              && len > REGISTER_SIZE)
+       {
+         /* All subsequent args go onto the stack. */
+         mcore_insn_debug (("MCORE PUSH: does not fit into regs, going onto stack\n"));
+         argnum = LAST_ARGREG + 1;
+       }
+
+      if (len > 0)
+       {
+         /* Note that this must be saved onto the stack */
+         mcore_insn_debug (("MCORE PUSH: adding arg %d to stack\n", argnum));
+         stack_args[nstack_args].val = val;
+         stack_args[nstack_args].len = len;
+         nstack_args++;
+       }
+
+    }
+
+  /* We're done with registers and stack allocation. Now do the actual
+     stack pushes. */
+  while (nstack_args--)
+    {
+      sp -= stack_args[nstack_args].len;
+      write_memory (sp, stack_args[nstack_args].val, stack_args[nstack_args].len);
+    }
+
+  /* Return adjusted stack pointer.  */
+  return sp;
+}
+
+/* Store the return address for the call dummy. For MCore, we've
+   opted to use generic call dummies, so we simply store the
+   CALL_DUMMY_ADDRESS into the PR register (r15). */
+
+CORE_ADDR
+mcore_push_return_address (CORE_ADDR pc, CORE_ADDR sp)
+{
+  write_register (PR_REGNUM, CALL_DUMMY_ADDRESS ());
+  return sp;
+}
+
+/* Setting/getting return values from functions.
+
+   The Motorola MCore processors use r2/r3 to return anything
+   not larger than 32 bits. Everything else goes into a caller-
+   supplied buffer, which is passed in via a hidden first
+   argument.
+
+   For gdb, this leaves us two routes, based on what
+   USE_STRUCT_CONVENTION (mcore_use_struct_convention) returns.
+   If this macro returns 1, gdb will call STORE_STRUCT_RETURN and
+   EXTRACT_STRUCT_VALUE_ADDRESS.
+
+   If USE_STRUCT_CONVENTION retruns 0, then gdb uses STORE_RETURN_VALUE
+   and EXTRACT_RETURN_VALUE to store/fetch the functions return value. */
+
+/* Should we use EXTRACT_STRUCT_VALUE_ADDRESS instead of
+   EXTRACT_RETURN_VALUE?  GCC_P is true if compiled with gcc
+   and TYPE is the type (which is known to be struct, union or array). */
+
+int
+mcore_use_struct_convention (int gcc_p, struct type *type)
+{
+  return (TYPE_LENGTH (type) > 8);
+}
+
+/* Where is the return value saved? For MCore, a pointer to 
+   this buffer was passed as a hidden first argument, so
+   just return that address. */
+
+CORE_ADDR
+mcore_extract_struct_value_address (char *regbuf)
+{
+  return extract_address (regbuf + REGISTER_BYTE (FIRST_ARGREG), REGISTER_SIZE);
+}
+
+/* Given a function which returns a value of type TYPE, extract the
+   the function's return value and place the result into VALBUF.
+   REGBUF is the register contents of the target. */
+
+void
+mcore_extract_return_value (struct type *type, char *regbuf, char *valbuf)
+{
+  /* Copy the return value (starting) in RETVAL_REGNUM to VALBUF. */
+  /* Only getting the first byte! if len = 1, we need the last byte of
+     the register, not the first. */
+  memcpy (valbuf, regbuf + REGISTER_BYTE (RETVAL_REGNUM) +
+  (TYPE_LENGTH (type) < 4 ? 4 - TYPE_LENGTH (type) : 0), TYPE_LENGTH (type));
+}
+
+/* Store the return value in VALBUF (of type TYPE) where the caller
+   expects to see it.
+
+   Values less than 32 bits are stored in r2, right justified and
+   sign or zero extended.
+
+   Values between 32 and 64 bits are stored in r2 (most
+   significant word) and r3 (least significant word, left justified).
+   Note that this includes structures of less than eight bytes, too. */
+
+void
+mcore_store_return_value (struct type *type, char *valbuf)
+{
+  int value_size;
+  int return_size;
+  int offset;
+  char *zeros;
+
+  value_size = TYPE_LENGTH (type);
+
+  /* Return value fits into registers. */
+  return_size = (value_size + REGISTER_SIZE - 1) & ~(REGISTER_SIZE - 1);
+  offset = REGISTER_BYTE (RETVAL_REGNUM) + (return_size - value_size);
+  zeros = alloca (return_size);
+  memset (zeros, 0, return_size);
+
+  write_register_bytes (REGISTER_BYTE (RETVAL_REGNUM), zeros, return_size);
+  write_register_bytes (offset, valbuf, value_size);
+}
+
+/* Initialize our target-dependent "stuff" for this newly created frame.
+
+   This includes allocating space for saved registers and analyzing
+   the prologue of this frame. */
+
+void
+mcore_init_extra_frame_info (struct frame_info *fi)
+{
+  if (fi->next)
+    fi->pc = FRAME_SAVED_PC (fi->next);
+
+  frame_saved_regs_zalloc (fi);
+
+  fi->extra_info = (struct frame_extra_info *)
+    frame_obstack_alloc (sizeof (struct frame_extra_info));
+  fi->extra_info->status = 0;
+  fi->extra_info->framesize = 0;
+
+  if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
+    {
+      /* We need to setup fi->frame here because run_stack_dummy gets it wrong
+         by assuming it's always FP.  */
+      fi->frame = generic_read_register_dummy (fi->pc, fi->frame, SP_REGNUM);
+    }
+  else
+    mcore_analyze_prologue (fi, 0, 0);
+}
+
+/* Get an insturction from memory. */
+
+static int
+get_insn (CORE_ADDR pc)
+{
+  char buf[4];
+  int status = read_memory_nobpt (pc, buf, 2);
+  if (status != 0)
+    return 0;
+
+  return extract_unsigned_integer (buf, 2);
+}
+
+void
+_initialize_mcore_tdep ()
+{
+  extern int print_insn_mcore (bfd_vma, disassemble_info *);
+  tm_print_insn = print_insn_mcore;
+
+#ifdef MCORE_DEBUG
+  add_show_from_set (add_set_cmd ("mcoredebug", no_class,
+                                 var_boolean, (char *) &mcore_debug,
+                                 "Set mcore debugging.\n", &setlist),
+                    &showlist);
+#endif
+}