Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* Re: A better register interface
       [not found] <3A8B5C60.92EEABA3@cygnus.com>
@ 2001-02-14 22:20 ` Nick Duffek
  2001-02-15  7:38   ` Fernando Nasser
  2001-02-15  8:40   ` Andrew Cagney
  0 siblings, 2 replies; 3+ messages in thread
From: Nick Duffek @ 2001-02-14 22:20 UTC (permalink / raw)
  To: gdb-patches

On 14-Feb-2001, Andrew Cagney wrote in gdb@sources.redhat.com:

>As many people will tell you GDB's current register interface/model is
>so large you can comfortably drive a road train through it.

[...]

>Associated with this are a number of bugs.  The most common are:

>	o	you can't get a complex pseudo
>		register from a saved frame

>	o	you can't modify a complex pseudo

>	o	you can only print complex psuedos
>		by a hack - have it backed by a
>		read only buffer.

>	o	the RAW_REGISTER_BYTE() macro determines
>		everything including the format of the
>		remote G packet.

>(a complex pseudo is one that is constructed from random bits from the
>register cache or stack).

Here is the revamped register cache interface patch.  It fixes all of the
above.

Since the last time I posted the patch, I modified it to address the
concerns you raised in January.  Specifically:

On 13-Jan-2001, Andrew Cagney wrote:

>Looking at one of the functions:

> real_register (int regnum)

[...]

>I think these should be made virtual so that your, or any other, code
>can just drop in..

Done.  I added several gdbarch.sh macros so that e.g. real_register() in
regcache.c is now REAL_REGISTER().

>I'm confused.  Your saying that the CLI changes depend on regs.c?  I
>think that is wrong.  It should be possible to code the cli so that it
>doesn't specificly depend on regs.c.

I've re-coded it so that cli-regs.c can be used without regs.c.

On 14-Jan-2001, Andrew Cagney wrote:

>The gdbarch_data() or gdbarch_memory() stuff should do what you need. 
>Just put the REGISTER_LIST in one of them.

Also done.  I've made use of the new set_gdbarch_data() function to remove
REGISTER_LIST from gdbarch.sh.

There are no regressions on i686-pc-linux-gnu or d10v-unknown-elf.

It works well on 2 not-yet-public architectures, and several GDB engineers
have expressed interest in using it.

Okay to apply?

Nick

ChangeLog:

	* Makefile.in (SUBDIR_CLI_OBS): Add cli-regs.o.
	(SUBDIR_CLI_SRCS): Add cli/cli-regs.c.
	(SFILES): Add regs.c.
	(regs_h): New variable.
	(COMMON_OBS): Add regs.o.
	(INIT_FILES): Add $(SUBDIR_CLI_SRCS).
	(regcache.o): Remove spurious trailing space.
	(regs.o, cli-regs.o): New rules.
	* cli/cli-regs.c: New file.
	* cli/cli-regs.h: New file.
	* defs.h (read_relative_register_raw_bytes): Move to value.h.
	* findvar.c (value_of_register, value_from_register): Change
	register_cached to REGISTER_CACHED.
	* gdbarch.sh (NUM_REGS): Document.
	(REGCACHE_MODULE_ACTIVE, REGISTER_NAME_TNUM, REGISTER_ADDR_TNUM,
	REGISTER_CACHED, SET_REGISTER_CACHED, REGISTER_BUFFER,
	REAL_REGISTER, PSEUDO_REGISTER, REGISTER_WRITE_MEMORY,
	REGISTER_INFO_FIRST, REGISTER_INFO_NEXT, REGISTER_HIDESOME,
	REGISTER_HIDEALL, REGISTER_RDONLY, REGISTER_REFFECT,
	FETCH_FRAME_REGISTER): New macros.
	* gdbarch.c: Regenerate.
	* gdbarch.h: Regenerate.
	* parse.c (target_map_name_to_register): Call
	REGISTER_NAME_TNUM() if available.
	* regcache.c: (set_register_cached): Update documentation.
	(register_changed, registers_changed, registers_fetched,
	fetch_register, store_register, read_register_bytes,
	read_relative_register_raw_bytes_for_frame,
	read_register_gen, write_register_gen, read_register,
	read_signed_register, write_register, supply_register): Uppercase
	register_cached, set_register_cached, pseudo_register,
	real_register, register_buffer.
	(read_relative_register_raw_bytes_for_frame, real_register,
	pseudo_register): Don't declare as static.
	(register_info_first, register_info_next, register_hidesome,
	register_hideall, register_rdonly, register_reffect,
	register_memonly, fetch_frame_register): New functions.
	(fetch_register): Issue error if neither real nor pseudo.
	(store_register): Likewise, and call REGISTER_RDONLY.
	(write_register_bytes): Call REGISTER_BUFFER instead of
	dereferencing registers[].
	(build_regcache): Omit initialization if !REGCACHE_MODULE_ACTIVE.
	* regs.c: New file.
	* regs.h: New file.
	* remote.c (supply_them): Uppercase set_register_cached.
	(store_register_using_P, remote_store_registers): Uppercase
	register_buffer.
	* target.c (do_xfer_memory): Call REGISTER_WRITE_MEMORY if
	available.
	* value.h (real_register, pseudo_register, register_info_first,
	register_info_next, register_hidesome, register_hideall,
	register_rdonly, register_reffect, register_memonly,
	fetch_frame_register, read_relative_register_raw_bytes,
	read_relative_register_raw_bytes_for_frame): Prototype.

Index: gdb/Makefile.in
===================================================================
diff -up gdb/Makefile.in gdb/Makefile.in
--- gdb/Makefile.in	Thu Feb 15 00:51:07 2001
+++ gdb/Makefile.in	Tue Feb 13 23:09:38 2001
@@ -141,10 +141,11 @@ INTL_CFLAGS = -I$(INTL_DIR) -I$(INTL_SRC
 # CLI sub directory definitons
 #
 SUBDIR_CLI_OBS = \
-	cli-decode.o cli-script.o cli-cmds.o cli-setshow.o cli-utils.o
+	cli-decode.o cli-script.o cli-cmds.o cli-setshow.o cli-utils.o \
+	cli-regs.o
 SUBDIR_CLI_SRCS = \
 	cli/cli-decode.c cli/cli-script.c cli/cli-cmds.c cli/cli-setshow.c \
-	cli/cli-utils.c
+	cli/cli-utils.c cli/cli-regs.c
 SUBDIR_CLI_DEPS =
 SUBDIR_CLI_INITS =
 SUBDIR_CLI_LDFLAGS=
@@ -519,6 +520,7 @@ SFILES = ax-general.c ax-gdb.c bcache.c 
 	kod.c kod-cisco.c \
 	ui-out.c cli-out.c \
 	varobj.c wrapper.c \
+	regs.c \
 	jv-exp.y jv-lang.c jv-valprint.c jv-typeprint.c \
 	m2-exp.y m2-lang.c m2-typeprint.c m2-valprint.c main.c maint.c \
 	memattr.c mem-break.c minsyms.c mipsread.c nlmread.c objfiles.c \
@@ -600,12 +602,14 @@ version_h = 	version.h
 ui_out_h =      ui-out.h
 cli_out_h =	cli-out.h
 arch_utils_h = arch-utils.h
+regs_h =	regs.h
 
 cli_decode_h =	$(srcdir)/cli/cli-decode.h
 cli_cmds_h =	$(srcdir)/cli/cli-cmds.h
 cli_script_h =	$(srcdir)/cli/cli-script.h
 cli_setshow_h =	$(srcdir)/cli/cli-setshow.h
 cli_utils_h =	$(srcdir)/cli/cli-utils.h
+cli_regs_h =	$(srcdir)/cli/cli-regs.h
 
 # Header files that need to have srcdir added.  Note that in the cases
 # where we use a macro like $(gdbcmd_h), things are carefully arranged
@@ -659,6 +663,7 @@ TAGFILES_NO_SRCDIR = $(SFILES) $(HFILES_
 TAGFILES_WITH_SRCDIR = $(HFILES_WITH_SRCDIR)
 
 COMMON_OBS = version.o blockframe.o breakpoint.o findvar.o regcache.o \
+	regs.o \
 	source.o values.o eval.o valops.o valarith.o valprint.o printcmd.o \
 	symtab.o symfile.o symmisc.o linespec.o infcmd.o infrun.o \
 	expprint.o environ.o stack.o thread.o \
@@ -781,7 +786,7 @@ uninstall: force $(CONFIG_UNINSTALL)
 # tui-file.c.
 #
 
-INIT_FILES = $(OBS) $(TSOBS) $(CONFIG_OBS) $(CONFIG_INITS)
+INIT_FILES = $(OBS) $(SUBDIR_CLI_SRCS) $(TSOBS) $(CONFIG_OBS) $(CONFIG_INITS)
 init.c: $(INIT_FILES)
 	@echo Making init.c
 	@rm -f init.c-tmp init.l-tmp
@@ -1342,7 +1347,10 @@ expprint.o: expprint.c $(defs_h) $(expre
 findvar.o: findvar.c $(defs_h) $(gdbcore_h) $(inferior_h) target.h \
 	gdb_string.h
 
-regcache.o: regcache.c $(defs_h) $(inferior_h) target.h 
+regcache.o: regcache.c $(defs_h) $(inferior_h) target.h
+
+regs.o: regs.c $(defs_h) $(inferior_h) $(arch_utils_h) \
+	$(gdbcore_h) $(symfile_h) $(regs_h)
 
 fork-child.o: fork-child.c gdb_wait.h $(defs_h) $(gdbcore_h) \
 	$(inferior_h) target.h terminal.h gdbthread.h gdb_string.h
@@ -2086,6 +2094,11 @@ cli-script.o: $(srcdir)/cli/cli-script.c
 
 cli-utils.o: $(srcdir)/cli/cli-utils.c $(cli_utils_h) $(defs_h)
 	$(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/cli/cli-utils.c
+
+cli-regs.o: $(srcdir)/cli/cli-regs.c $(cli_regs_h) \
+		$(defs_h) $(floatformat_h) $(frame_h) $(value_h) \
+		ui-file.h $(INCLUDE_DIR)/symcat.h
+	$(CC) -c $(INTERNAL_CFLAGS) $(srcdir)/cli/cli-regs.c
 
 #
 # MI dependencies
Index: gdb/cli/cli-regs.c
===================================================================
diff -up /dev/null gdb/cli/cli-regs.c
--- /dev/null	Sun Feb 12 03:29:56 1995
+++ gdb/cli/cli-regs.c	Tue Feb 13 23:39:34 2001
@@ -0,0 +1,725 @@
+/* GDB CLI register display library.
+   Copyright 2000 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 "cli/cli-utils.h"
+#include "floatformat.h"
+#include "ui-file.h"
+#include "symcat.h"
+#include "value.h"
+#include "frame.h"
+
+/* Minimum space between register name and values.  */
+
+#define NAMEGAP 2
+
+/* Minimum space between register hexadecimal and decimal/float values.  */
+
+#define HEXGAP 1
+
+/* Minimum space between columns.  */
+
+#define COLGAP 4
+
+/* Space between vector elements.  */
+
+#define VECGAP 2
+
+/* Screen width.  Should query terminal, but this works for a first cut.  */
+
+#define SCREENW 80
+
+/* Strings to display when register values are unavailable for various
+   reasons.  */
+
+#define DISP_INVFLOAT	"<invalid float>"
+#define DISP_NOVAL	"<error>"
+#define DISP_EFFECT	"<live>"
+
+/* Indices into 2-element arrays representing "info all-registers" and "info
+   registers" formatting information.  */
+
+#define SOME 0
+#define ALL 1
+
+/* Information about a register's value component display format.  */
+
+struct compfmt
+  {
+    unsigned int right : 1;	/* whether to right-justify instead of
+				   left-justify the component */
+    unsigned int width : 15;	/* width of justified component */
+    unsigned int gap : 15;	/* number of spaces to emit after the
+				   component if not wrapped */
+  };
+
+/* Information about a register's value display format.  */
+
+struct valfmt
+  {
+    struct reg *reg;		/* register to which this format applies */
+    int ncomps;			/* number of value components */
+    void (*display)		/* callback to display a component */
+      (struct reg *, int, char *, char *);
+    int width;			/* total width needed to display all value
+				   components */
+    struct compfmt *compfmts;	/* value component formats */
+  };
+
+/* Information about a register's display format in "info all-registers" or
+   "info registers" context.  */
+
+struct ctxtfmt
+  {
+    unsigned int hide : 1;	/* whether to hide the register in this
+				   context */
+    unsigned int namepad : 10;	/* number of spaces before the name */
+    unsigned int newline : 1;	/* whether to emit a newline after the
+				   last value component */
+    unsigned int gap : 10;	/* number of spaces after the last value
+				   component */
+    unsigned int namewrap : 10;	/* number of spaces to emit after wrapping
+				   between components */
+  };
+
+/* Per-register information.  */
+
+struct reg
+  {
+    int tnum;			/* register's target number */
+    struct type *type;		/* register's type */
+    int size;			/* register's size */
+    struct valfmt *valfmt;	/* value formattting information */
+    struct ctxtfmt ctxtfmt[2];	/* context-specific formatting information */
+  };
+
+/* Per-architecture information for internal use by this module.  */
+
+struct inf
+  {
+    struct reg *regs;		/* per-register information, in display
+				   order */
+    int nregs;			/* length of .regs */
+    struct valfmt *valfmts;	/* value formats referenced by .regs */
+    int nvalfmts;		/* length of .valfmts */
+    char *virtbuf;		/* for storing any virtual register value */
+    int prev_screenw;		/* screen width during most recent
+				   cliregs_info() call */
+  };
+
+/* Memory file buffer for formatting, needed for padding the results of
+   val_print().  */
+
+static struct ui_file *memfile = NULL;
+
+/* Identifier returned by register_gdbarch_data().  */
+
+static struct gdbarch_data *inf_id;
+
+/* Print the TYPE value in virtual BUF using val_print() FORMAT, right-padding
+   it to WIDTH characters if RIGHT and left-padding it otherwise.  */
+
+static void
+display_val (struct type *type, char *buf, int format, int right, int width)
+{
+  char *memstr;
+  long len;
+  struct cleanup *cleanups;
+
+  /* Clear the buffer passed to val_print(), creating it first if needed.  */
+  if (!memfile)
+    memfile = mem_fileopen ();
+  else
+    ui_file_rewind (memfile);
+
+  val_print (type, buf, 0, 0, memfile, format, 1, 0, Val_pretty_default);
+
+  memstr = ui_file_xstrdup (memfile, &len);
+  cleanups = make_cleanup (xfree, memstr);
+
+  printf_filtered (right ? "%*s" : "%-*s", width, memstr);
+  do_cleanups (cleanups);
+}
+
+/* Display component number I of vector register REG.  */
+
+static void
+display_vec (struct reg *reg, int i, char *rawbuf, char *virtbuf)
+{
+  struct type *type;
+  int elen;
+
+  /* Print components in hex.  */
+  type = TYPE_TARGET_TYPE (reg->type);
+  elen = TYPE_LENGTH (type);
+
+  display_val (type, virtbuf + i * elen, 'x', reg->valfmt->compfmts[i].right,
+	       reg->valfmt->compfmts[i].width);
+}
+
+/* Display component number I of normal register REG.  */
+
+static void
+display_hexdec (struct reg *reg, int i, char *rawbuf, char *virtbuf)
+{
+  /* Print non-floats in hex and decimal.  */
+  display_val (reg->type, virtbuf, i ? 'd' : 'x', reg->valfmt->compfmts[i].right,
+	       reg->valfmt->compfmts[i].width);
+}
+
+/* Display component number I of float register REG.  */
+
+static void
+display_float (struct reg *reg, int i, char *rawbuf, char *virtbuf)
+{
+  int j;
+  char *memstr;
+  long len;
+  struct cleanup *cleanups;
+
+  /* Print floats as numbers and hex strings.  */
+  if (!i)
+    {
+#ifdef INVALID_FLOAT
+      if (INVALID_FLOAT (virtbuf, TYPE_LENGTH (reg->type)))
+	printf_filtered ("%-*s", reg->valfmt->width, DISP_INVFLOAT);
+      else
+#endif
+	display_val (reg->type, virtbuf, 0, reg->valfmt->compfmts[i].right,
+		     reg->valfmt->compfmts[i].width);
+    }
+  else
+    {
+      if (!memfile)
+	memfile = mem_fileopen ();
+      else
+	ui_file_rewind (memfile);
+
+      fputs_unfiltered ("(raw 0x", memfile);
+      for (j = 0; j < reg->size; j++)
+	{
+	  int idx = TARGET_BYTE_ORDER == BIG_ENDIAN ? j
+	    : reg->size - 1 - j;
+	  fprintf_unfiltered (memfile, "%02x", (unsigned char) rawbuf[idx]);
+	}
+      fputc_unfiltered (')', memfile);
+
+      memstr = ui_file_xstrdup (memfile, &len);
+      cleanups = make_cleanup (xfree, memstr);
+
+      puts_filtered (memstr);
+      do_cleanups (cleanups);
+    }
+}
+
+/* Return the index in INF->valfmts of the format to be used for REG, creating
+   the format if it doesn't exist.
+
+   FIXME: this should call methods in struct language_defn.  */
+
+static int
+init_valfmt (struct inf *inf, struct reg *reg)
+{
+  int len, slen, elen, i;
+  const char *unavail[] = { DISP_NOVAL, DISP_EFFECT, NULL };
+  struct valfmt *valfmt;
+  enum type_code code, code2;
+  struct compfmt *compfmts;
+
+  len = TYPE_LENGTH (reg->type);
+  code = TYPE_CODE (reg->type);
+
+  /* Search for a format for TYPE and SIZE in INF->valfmts.  This uses
+     in-depth knowledge of how all values are formatted, so it'll probably
+     become obsolete if this function is ever fixed to call language_defn
+     methods.
+
+     Running time for this search is O(n^2), where n is the number of register
+     formats in the current architecture.  */
+  for (i = 0; i < inf->nvalfmts; i++)
+    {
+      valfmt = inf->valfmts + i;
+
+      /* Length and raw size must match.  */
+      if (valfmt->reg->size != reg->size)
+	continue;
+      if (len != TYPE_LENGTH (valfmt->reg->type))
+	continue;
+
+      /* Float matches float, vector matches vector, anything else matches
+         anything else.  */
+      code2 = TYPE_CODE (valfmt->reg->type);
+      if (code != code2)
+	{
+	  if (code == TYPE_CODE_FLT || code2 == TYPE_CODE_FLT)
+	    continue;
+	  if (code == TYPE_CODE_ARRAY || code2 == TYPE_CODE_ARRAY)
+	    continue;
+	}
+
+      /* Vector element lengths must match.  */
+      else if (code == TYPE_CODE_ARRAY
+	       && (TYPE_LENGTH (TYPE_TARGET_TYPE (reg->type))
+		   != TYPE_LENGTH (TYPE_TARGET_TYPE (valfmt->reg->type))))
+	continue;
+
+      /* Found a matching format.  */
+      return i;
+    }
+
+  /* Create a new format.  */
+  inf->nvalfmts++;
+  valfmt = inf->valfmts + inf->nvalfmts - 1;
+  valfmt->reg = reg;
+
+  /* Vectors get printed as a VECGAP-separated hexadecimal list.  */
+  if (code == TYPE_CODE_ARRAY)
+    {
+      elen = TYPE_LENGTH (TYPE_TARGET_TYPE (reg->type));
+      valfmt->ncomps = len / elen;
+      valfmt->compfmts = compfmts = xmalloc (valfmt->ncomps
+					     * sizeof *valfmt->compfmts);
+      for (i = 0; i < valfmt->ncomps; i++)
+	{
+	  compfmts[i].right = 1;
+	  compfmts[i].width = 2 + elen * 2;
+	  compfmts[i].gap = VECGAP;
+	}
+      valfmt->width = (2 + elen * 2) * valfmt->ncomps
+	+ VECGAP * (valfmt->ncomps - 1);
+      valfmt->display = display_vec;
+    }
+
+  /* Floats get printed as floats followed by "(raw <hex>)".  */
+  else if (code == TYPE_CODE_FLT)
+    {
+      valfmt->ncomps = 2;
+      valfmt->compfmts = compfmts = xmalloc (2 * sizeof *valfmt->compfmts);
+
+      /* print_floating() gives floats more digits than they need, so use its
+         hard-coded values rather than inferring from float width.  FIXME:
+         fix print_floating(), then change this accordingly.  */
+
+      compfmts[0].right = 0;
+      compfmts[0].gap = HEXGAP;
+
+      if (len < sizeof (double))
+	compfmts[0].width = 11;
+      else if (len == sizeof (double))
+	compfmts[0].width = 19;
+#ifdef PRINTF_HAS_LONG_DOUBLE
+      else
+	compfmts[0].width = 37;
+#else
+      else
+	compfmts[0].width = 19;
+#endif
+
+      compfmts[1].right = 0;
+      compfmts[1].width = (8 +			/* (raw 0x) */
+			   reg->size * 2);	/* 2 hex digits per byte */
+
+      valfmt->width = compfmts[0].width + HEXGAP + compfmts[1].width;
+      slen = sizeof (DISP_INVFLOAT) - 1;
+      if (valfmt->width < slen)
+	valfmt->width = slen;
+
+      valfmt->display = display_float;
+    }
+
+  /* Everything else gets printed in hex followed by signed decimal.  */
+  else
+    {
+      valfmt->ncomps = 2;
+      valfmt->compfmts = compfmts = xmalloc (2 * sizeof *valfmt->compfmts);
+
+      compfmts[0].right = 1;
+      compfmts[0].gap = HEXGAP;
+      compfmts[0].width = (2 +		/* 0x */
+			   len * 2);	/* 2 hex digits per byte */
+
+      compfmts[1].right = 1;
+      compfmts[1].width = 1;		/* sign */
+      if (len == 1)
+	compfmts[1].width += 3;		/* 3 digits for 1-byte value */
+      else
+	compfmts[1].width += len * 5 / 2; /* poor man's base-10 logarithm */
+
+      valfmt->width = compfmts[0].width + HEXGAP + compfmts[1].width;
+
+      valfmt->display = display_hexdec;
+    }
+
+  /* Unavailable-value strings.  */
+  for (i = 0; unavail[i]; i++)
+    if (valfmt->width < (len = strlen (unavail[i])))
+      valfmt->width = len;
+
+  return inf->nvalfmts - 1;
+}
+
+/* Calculate column layout for each register in both "info registers" and
+   "info all-registers" output.  Algorithm:
+
+   (1) Divide the registers into subsets where all members of a subset
+       have the same value format.
+
+   (2) Find the maximum name length in each subset.
+
+   (3) Pad register names to the maximum lengths found in (2).
+
+   (4) Calculate the maximum number of columns across which registers in
+       each subset can be distributed, and distribute them accordingly.  */
+
+static void
+init_columns (struct inf *inf)
+{
+  int i, j, *reg_valfmti, *valfmti_namemax[2], namelen, valfmti;
+  struct reg *reg;
+  char *name;
+
+  inf->nvalfmts = 0;
+
+  /* Register display formats.  */
+  inf->valfmts = xmalloc (inf->nregs * sizeof (struct valfmt));
+
+  /* Format indices versus maximum name lengths, for implementing both (1)
+     and (2).  */
+  for (i = SOME; i <= ALL; i++)
+    valfmti_namemax[i] = xcalloc (inf->nregs, sizeof (int));
+
+  /* Register indices versus format numbers, for caching init_valfmt().  */
+  reg_valfmti = xmalloc (inf->nregs * sizeof (int));
+
+  for (i = SOME; i <= ALL; i++)
+    {
+      /* (1) and (2): create subsets, calculate max name lengths.  */
+      for (j = 0; j < inf->nregs; j++)
+	{
+	  reg = inf->regs + j;
+
+	  if (REGISTER_HIDEALL (reg->tnum))
+	    reg->ctxtfmt[i].hide = 1;
+	  else if (i == SOME && REGISTER_HIDESOME (reg->tnum))
+	    reg->ctxtfmt[i].hide = 1;
+	  else
+	    reg->ctxtfmt[i].hide = 0;
+
+	  if (i == ALL)
+	    valfmti = reg_valfmti[j];
+	  else
+	    reg_valfmti[j] = valfmti = init_valfmt (inf, reg);
+
+	  if (!reg->ctxtfmt[i].hide)
+	    {
+	      namelen = strlen (REGISTER_NAME (reg->tnum));
+	      if (namelen > valfmti_namemax[i][valfmti])
+		valfmti_namemax[i][valfmti] = namelen;
+	    }
+	}
+    }
+
+  /* Free unused space.  */
+  inf->valfmts = xrealloc (inf->valfmts, inf->nvalfmts
+			   * sizeof (struct valfmt));
+
+  for (i = SOME; i <= ALL; i++)
+    {
+      /* (1) and (3): finish creating subsets, pad register names.  */
+      for (j = 0; j < inf->nregs; j++)
+	{
+	  reg = inf->regs + j;
+	  valfmti = reg_valfmti[j];
+	  reg->valfmt = inf->valfmts + valfmti;
+
+	  /* Pad register name.  */
+	  if (reg->ctxtfmt[i].hide)
+	    {
+	      reg->ctxtfmt[i].namepad = 0;
+	      reg->ctxtfmt[i].namewrap = 0;
+	    }
+	  else
+	    {
+	      name = REGISTER_NAME (reg->tnum);
+	      reg->ctxtfmt[i].namepad =
+		valfmti_namemax[i][valfmti] - strlen (name);
+	      reg->ctxtfmt[i].namewrap = 
+		1 + valfmti_namemax[i][valfmti] + NAMEGAP;
+	    }
+	}
+    }
+
+  for (i = SOME; i <= ALL; i++)
+    free (valfmti_namemax[i]);
+  free (reg_valfmti);
+}
+
+/* Update INF for screen width SCREENW.  FIXME: arrange for this to be called
+   from cliregs_info() if the screen width has changed.  */
+
+static void
+set_screenw (struct inf *inf, int screenw)
+{
+  int i, j, *valfmti_ncols, valfmti_prev, valfmti, col, width;
+  struct reg *reg, *reg_prev;
+
+  /* Format indices versus column counts, for implementing (4).  */
+  valfmti_ncols = xcalloc (inf->nvalfmts, sizeof (int));
+
+  for (i = SOME; i <= ALL; i++)
+    {
+      /* (4): Calculate columns.  */
+      reg_prev = NULL;
+      valfmti_prev = -1;
+      col = 0;
+
+      for (j = 0; j < inf->nregs; j++)
+	{
+	  reg = inf->regs + j;
+	  if (reg->ctxtfmt[i].hide)
+	    {
+	      reg->ctxtfmt[i].newline = 1;
+	      reg->ctxtfmt[i].gap = 0;
+	      continue;
+	    }
+
+	  valfmti = reg->valfmt - inf->valfmts;
+	  if (!valfmti_ncols[valfmti])
+	    {
+	      width = reg->ctxtfmt[i].namewrap + reg->valfmt->width;
+	      valfmti_ncols[valfmti] = (screenw + COLGAP) / (width + COLGAP);
+	      if (valfmti_ncols[valfmti] <= 0)
+		valfmti_ncols[valfmti] = 1;
+	    }
+
+	  /* Start a new line if the value won't fit on the current one or if
+	     its format differs from the previous register value's.  */
+	  if (valfmti_prev != valfmti || col++ == valfmti_ncols[valfmti])
+	    col = 1;
+	  else
+	    {
+	      reg_prev->ctxtfmt[i].newline = 0;
+	      reg_prev->ctxtfmt[i].gap = COLGAP;
+	    }
+
+	  reg->ctxtfmt[i].newline = 1;
+	  reg->ctxtfmt[i].gap = 0;
+	  valfmti_prev = valfmti;
+	  reg_prev = reg;
+	}
+    }
+
+  free (valfmti_ncols);
+}
+
+/* Initialize INF->regs and INF->nregs.  */
+
+static void
+init_regs (struct inf *inf)
+{
+  struct reg *reg;
+  int tnum;
+  char *name;
+
+  inf->regs = xmalloc ((NUM_REGS + NUM_PSEUDO_REGS) * sizeof (struct reg));
+  inf->nregs = 0;
+
+  for (tnum = REGISTER_INFO_FIRST (); tnum >= 0;
+       tnum = REGISTER_INFO_NEXT (tnum))
+    {
+      name = REGISTER_NAME (tnum);
+      if (!name || !*name)
+	continue;
+
+      reg = inf->regs + inf->nregs++;
+      reg->tnum = tnum;
+      reg->type = REGISTER_VIRTUAL_TYPE (tnum);
+      reg->size = REGISTER_RAW_SIZE (tnum);
+    }
+
+  /* Free unused memory.  */
+  inf->regs = xrealloc (inf->regs, inf->nregs * sizeof (struct reg));
+}
+
+/* Update INF to reflect the current screen size, initializing INF first if
+   necessary.  */
+
+static void
+update_inf (struct inf *inf)
+{
+  int init, screenw;
+
+  if ((init = !inf->regs))
+    {
+      init_regs (inf);
+      init_columns (inf);
+      inf->virtbuf = xmalloc (MAX_REGISTER_VIRTUAL_SIZE);
+    }
+
+  screenw = SCREENW;
+  if (init || screenw != inf->prev_screenw)
+    {
+      set_screenw (inf, SCREENW);
+      inf->prev_screenw = screenw;
+    }
+}
+
+/* Display the register whose target number is TNUM.  If TNUM is -1, print all
+   registers (all == 1) or some registers (all == 0).
+
+   To reduce the number of pages per register dump, use multi-column layout if
+   possible.  Layout rules:
+
+     - Registers are displayed from left -> right and then top -> bottom in
+       the internal register ordering.
+
+     - All registers with the same value format are distributed across the
+       same number of columns, within which values are vertically aligned.
+
+     - A multi-value register is displayed starting on a new line if some but
+       not all of its values will fit on the previous line.  */
+
+static void
+cliregs_info (int tnum, int all)
+{
+  int i, j, from, to, multi, width, gap, offset;
+  struct reg *reg;
+  struct inf *inf;
+  struct ctxtfmt *ctxtfmt;
+  char *rawbuf;
+
+  inf = gdbarch_data (inf_id);
+  update_inf (inf);
+
+  rawbuf = (char *) alloca (MAX_REGISTER_RAW_SIZE);
+  multi = tnum == -1;
+
+  /* Display registers.  */
+  for (i = 0; i < inf->nregs; i++)
+    {
+      reg = inf->regs + i;
+      if (!multi && reg->tnum != tnum)
+	continue;
+
+      if (multi)
+	ctxtfmt = &reg->ctxtfmt[all ? ALL : SOME];
+      else
+	ctxtfmt = &reg->ctxtfmt[REGISTER_HIDESOME (reg->tnum) ? ALL : SOME];
+
+      if (multi && ctxtfmt->hide)
+	continue;
+
+      /* Display name.  */
+      printf_filtered ("%-*s$%s%" XSTRING (NAMEGAP) "s",
+		       ctxtfmt->namepad, "", REGISTER_NAME (reg->tnum), "");
+      offset = ctxtfmt->namewrap;
+
+      /* Don't display registers with side-effects unless explicitly
+	 requested. */
+      if (multi && REGISTER_REFFECT (reg->tnum))
+	{
+	  puts_filtered (DISP_EFFECT);
+	  offset += strlen (DISP_EFFECT);
+	}
+
+      /* Try to retrieve raw value.  */
+      else if (FETCH_FRAME_REGISTER (selected_frame, reg->tnum, rawbuf) <= 0)
+	{
+	  puts_filtered (DISP_NOVAL);
+	  offset += strlen (DISP_NOVAL);
+	}
+
+      /* Display the retrieved value.  */
+      else
+	{
+	  /* Convert to virtual.  */
+	  if (!REGISTER_CONVERTIBLE (reg->tnum))
+	    memcpy (inf->virtbuf, rawbuf, TYPE_LENGTH (reg->type));
+	  else
+	    REGISTER_CONVERT_TO_VIRTUAL (reg->tnum, reg->type, rawbuf,
+					 inf->virtbuf);
+
+	  /* Display value components.  */
+	  for (j = 0; j < reg->valfmt->ncomps; j++)
+	    {
+	      width = reg->valfmt->compfmts[j].width;
+	      if (j)
+		{
+		  gap = reg->valfmt->compfmts[j - 1].gap;
+		  if (offset + gap + width > SCREENW)
+		    {
+		      printf_filtered ("\n%*s", ctxtfmt->namewrap, "");
+		      offset = ctxtfmt->namewrap;
+		    }
+		  else
+		    {
+		      printf_filtered ("%*s", gap, "");
+		      offset += gap;
+		    }
+		}
+	      reg->valfmt->display (reg, j, rawbuf, inf->virtbuf);
+	      offset += width;
+	    }
+	}
+
+      /* Print column gap or newline.  */
+      if (ctxtfmt->newline || !multi)
+	putchar_filtered ('\n');
+      else
+	{
+	  gap = ctxtfmt->gap;
+	  offset -= ctxtfmt->namewrap;
+	  if (offset < reg->valfmt->width)
+	    gap += reg->valfmt->width - offset;
+	  printf_filtered ("%*s", gap, "");
+	}
+    }
+}
+
+/* Initialize GDBARCH fields handled by this module.  Architectures should
+   call this function from their gdbarch_register() callbacks.  */
+
+void
+cliregs_init (struct gdbarch *gdbarch)
+{
+  struct inf *inf;
+
+  /* To avoid allocating space for architectures not using cliregs_info(),
+     assign GDBARCH's struct inf here rather than via a
+     register_gdbarch_data() callback.
+
+     struct inf initialization requires gdbarch.sh macros that require a valid
+     current_gdbarch.  Therefore, postpone initialization until the first
+     cliregs_info() call.  */
+
+  inf = xmalloc (sizeof (struct inf));
+  inf->regs = NULL;
+  set_gdbarch_data (gdbarch, inf_id, inf);
+
+  set_gdbarch_do_registers_info (gdbarch, cliregs_info);
+}
+
+/* Module initialization.  */
+
+void
+_initialize_cliregs (void)
+{
+  inf_id = register_gdbarch_data (NULL, NULL);
+}
Index: gdb/cli/cli-regs.h
===================================================================
diff -up /dev/null gdb/cli/cli-regs.h
--- /dev/null	Sun Feb 12 03:29:56 1995
+++ gdb/cli/cli-regs.h	Tue Feb 13 23:09:38 2001
@@ -0,0 +1,26 @@
+/* Header file for GDB CLI register display library.
+   Copyright (C) 2000 Free Software Foundation, Inc.
+
+   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.  */
+
+#if !defined (CLI_REGS_H)
+# define CLI_REGS_H 1
+
+/* Architecture initialization routine.  */
+
+extern void cliregs_init (struct gdbarch *);
+
+#endif /* !defined (CLI_REGS_H) */
Index: gdb/defs.h
===================================================================
diff -up gdb/defs.h gdb/defs.h
--- gdb/defs.h	Thu Feb 15 00:51:26 2001
+++ gdb/defs.h	Tue Feb 13 23:09:38 2001
@@ -584,10 +584,6 @@ extern void exec_set_section_offsets (bf
 				      bfd_signed_vma data_off,
 				      bfd_signed_vma bss_off);
 
-/* From findvar.c */
-
-extern int read_relative_register_raw_bytes (int, char *);
-
 /* Possible lvalue types.  Like enum language, this should be in
    value.h, but needs to be here for the same reason. */
 
Index: gdb/findvar.c
===================================================================
diff -up gdb/findvar.c gdb/findvar.c
--- gdb/findvar.c	Thu Feb 15 00:51:34 2001
+++ gdb/findvar.c	Tue Feb 13 23:09:38 2001
@@ -401,7 +401,7 @@ value_of_register (int regnum)
   get_saved_register (raw_buffer, &optim, &addr,
 		      selected_frame, regnum, &lval);
 
-  if (register_cached (regnum) < 0)
+  if (REGISTER_CACHED (regnum) < 0)
     return NULL;		/* register value not available */
 
   reg_val = allocate_value (REGISTER_VIRTUAL_TYPE (regnum));
@@ -795,7 +795,7 @@ value_from_register (struct type *type, 
 			      page_regnum,
 			      &lval);
 
-	  if (register_cached (page_regnum) == -1)
+	  if (REGISTER_CACHED (page_regnum) == -1)
 	    return NULL;	/* register value not available */
 
 	  if (lval == lval_register)
@@ -812,7 +812,7 @@ value_from_register (struct type *type, 
 			      regnum,
 			      &lval);
 
-	  if (register_cached (regnum) == -1)
+	  if (REGISTER_CACHED (regnum) == -1)
 	    return NULL;	/* register value not available */
 
 	  if (lval == lval_register)
@@ -838,7 +838,7 @@ value_from_register (struct type *type, 
 				local_regnum,
 				&lval);
 
-	    if (register_cached (local_regnum) == -1)
+	    if (REGISTER_CACHED (local_regnum) == -1)
 	      return NULL;	/* register value not available */
 
 	    if (regnum == local_regnum)
@@ -904,7 +904,7 @@ value_from_register (struct type *type, 
 
   get_saved_register (raw_buffer, &optim, &addr, frame, regnum, &lval);
 
-  if (register_cached (regnum) == -1)
+  if (REGISTER_CACHED (regnum) == -1)
     return NULL;		/* register value not available */
 
   VALUE_OPTIMIZED_OUT (v) = optim;
Index: gdb/gdbarch.sh
===================================================================
diff -up gdb/gdbarch.sh gdb/gdbarch.sh
--- gdb/gdbarch.sh	Thu Feb 15 00:52:19 2001
+++ gdb/gdbarch.sh	Tue Feb 13 23:09:38 2001
@@ -358,7 +358,7 @@ f::TARGET_READ_FP:CORE_ADDR:read_fp:void
 f::TARGET_WRITE_FP:void:write_fp:CORE_ADDR val:val::0:generic_target_write_fp::0
 f::TARGET_READ_SP:CORE_ADDR:read_sp:void:::0:generic_target_read_sp::0
 f::TARGET_WRITE_SP:void:write_sp:CORE_ADDR val:val::0:generic_target_write_sp::0
-#
+# Number of real (not pseudo) registers.
 v:2:NUM_REGS:int:num_regs::::0:-1
 # This macro gives the number of pseudo-registers that live in the
 # register namespace but do not get fetched or stored on the target.
@@ -392,6 +392,54 @@ f:2:REGISTER_VIRTUAL_SIZE:int:register_v
 v:2:MAX_REGISTER_VIRTUAL_SIZE:int:max_register_virtual_size::::0:-1
 f:2:REGISTER_VIRTUAL_TYPE:struct type *:register_virtual_type:int reg_nr:reg_nr::0:0
 f:2:DO_REGISTERS_INFO:void:do_registers_info:int reg_nr, int fpregs:reg_nr, fpregs:::do_registers_info::0
+# Whether regcache.c's register cache is active.
+v:2:REGCACHE_MODULE_ACTIVE:int:regcache_module_active:::::1::0
+# Return the target number of the register with LEN-byte NAME, or -1 if no
+# such register exists.
+F:2:REGISTER_NAME_TNUM:int:register_name_tnum:char *name, int len:name, len::0
+# Return the target number of the register mapped to memory ADDR, or -1 if no
+# such register exists.
+F:2:REGISTER_ADDR_TNUM:int:register_addr_tnum:CORE_ADDR addr:addr::0
+# Return >0 if register REGNUM's value in the innermost frame is cached, 0 if
+# it's uncached but fetchable, and <0 if it's uncached and unfetchable.
+f:2:REGISTER_CACHED:int:register_cached:int regnum:regnum:::register_cached::0
+# Record that TNUM's value is cached if STATE is >0, uncached but fetchable if
+# STATE is 0, and uncached and unfetchable if STATE is <0.
+#
+# This function must be called whenever a register's cached state changes,
+# including when updating a valid value with a new valid value.
+f:2:SET_REGISTER_CACHED:void:set_register_cached:int regnum, int state:regnum, state:::set_register_cached::0
+# If REGNUM >= 0, return a pointer to register REGNUM's cache buffer area,
+# else return a pointer to the start of the cache buffer.
+f:2:REGISTER_BUFFER:char *:register_buffer:int regnum:regnum:::register_buffer::0
+# Return whether register REGNUM is a real (not pseudo) register.
+f:2:REAL_REGISTER:int:real_register:int regnum:regnum:::real_register::0
+# Return whether register REGNUM is a pseudo register.
+f:2:PSEUDO_REGISTER:int:pseudo_register:int regnum:regnum:::pseudo_register::0
+# Invalidate any memory-mapped registers that the LEN-byte target memory
+# region starting at ADDR overlaps.  This function should be called whenever
+# target memory is written.
+F:2:REGISTER_WRITE_MEMORY:void:register_write_memory:CORE_ADDR addr, int len:addr, len::0
+# Return the target number of the first register that "info registers" and
+# "info all-registers" should consider for display.
+f:2:REGISTER_INFO_FIRST:int:register_info_first:void::::register_info_first::0
+# Return the target number of the register that "info registers" and "info
+# all-registers" should consider for display after register REGNUM.  If no
+# registers should be displayed after register REGNUM, return -1.
+f:2:REGISTER_INFO_NEXT:int:register_info_next:int regnum:regnum:::register_info_next::0
+# Return whether register REGNUM should be omitted from "info registers"
+# display.
+f:2:REGISTER_HIDESOME:int:register_hidesome:int regnum:regnum:::register_hidesome::0
+# Return whether register REGNUM should be omitted from "info registers"
+# and "info all-registers" display.
+f:2:REGISTER_HIDEALL:int:register_hideall:int regnum:regnum:::register_hideall::0
+# Return whether register REGNUM is read-only.
+f:2:REGISTER_RDONLY:int:register_rdonly:int regnum:regnum:::register_rdonly::0
+# Return whether side-effects result from reading register REGNUM.
+f:2:REGISTER_REFFECT:int:register_reffect:int regnum:regnum:::register_reffect::0
+# Try to fetch register REGNUM's value from FRAME into RAWBUF.  Return 1 on
+# success, 0 on failure if a future attempt might succeed, -1 otherwise.
+f:2:FETCH_FRAME_REGISTER:int:fetch_frame_register:struct frame_info *frame, int regnum, char *rawbuf:frame, regnum, rawbuf:::fetch_frame_register::0
 # MAP a GDB RAW register number onto a simulator register number.  See
 # also include/...-sim.h.
 f:2:REGISTER_SIM_REGNO:int:register_sim_regno:int reg_nr:reg_nr:::default_register_sim_regno::0
Index: gdb/parse.c
===================================================================
diff -up gdb/parse.c gdb/parse.c
--- gdb/parse.c	Thu Feb 15 00:52:25 2001
+++ gdb/parse.c	Tue Feb 13 23:09:38 2001
@@ -116,6 +116,9 @@ target_map_name_to_register (char *str, 
 {
   int i;
 
+  if (REGISTER_NAME_TNUM_P ())
+    return REGISTER_NAME_TNUM (str, len);
+
   /* First try target specific aliases. We try these first because on some 
      systems standard names can be context dependent (eg. $pc on a 
      multiprocessor can be could be any of several PCs).  */
Index: gdb/regcache.c
===================================================================
diff -up gdb/regcache.c gdb/regcache.c
--- gdb/regcache.c	Thu Feb 15 00:52:34 2001
+++ gdb/regcache.c	Wed Feb 14 01:30:47 2001
@@ -70,7 +70,10 @@ register_cached (int regnum)
 }
 
 /* Record that REGNUM's value is cached if STATE is >0, uncached but
-   fetchable if STATE is 0, and uncached and unfetchable if STATE is <0.  */
+   fetchable if STATE is 0, and uncached and unfetchable if STATE is <0.
+
+   This function must be called whenever a register's cached state changes,
+   including when updating a valid value with a new valid value.  */
 
 void
 set_register_cached (int regnum, int state)
@@ -84,7 +87,7 @@ set_register_cached (int regnum, int sta
 void
 register_changed (int regnum)
 {
-  set_register_cached (regnum, 0);
+  SET_REGISTER_CACHED (regnum, 0);
 }
 
 /* If REGNUM >= 0, return a pointer to register REGNUM's cache buffer area,
@@ -99,9 +102,9 @@ register_buffer (int regnum)
     return &registers[REGISTER_BYTE (regnum)];
 }
 
-/* Return whether register REGNUM is a real register.  */
+/* Return whether register REGNUM is a real (not pseudo) register.  */
 
-static int
+int
 real_register (int regnum)
 {
   return regnum >= 0 && regnum < NUM_REGS;
@@ -109,21 +112,100 @@ real_register (int regnum)
 
 /* Return whether register REGNUM is a pseudo register.  */
 
-static int
+int
 pseudo_register (int regnum)
 {
   return regnum >= NUM_REGS && regnum < NUM_REGS + NUM_PSEUDO_REGS;
 }
 
+/* Return the target number of the first register that "info registers" and
+   "info all-registers" should consider for display.  */
+
+int
+register_info_first (void)
+{
+  return 0;
+}
+
+/* Return the target number of the register that "info registers" and "info
+   all-registers" should consider for display after register REGNUM.  If no
+   registers should be displayed after register REGNUM, return -1.  */
+
+int
+register_info_next (int regnum)
+{
+  regnum++;
+  if (regnum >= NUM_REGS + NUM_PSEUDO_REGS)
+    return -1;
+  if (regnum >= ARCH_NUM_REGS && regnum < NUM_REGS)
+    return NUM_REGS;
+  return regnum;
+}
+
+/* Return whether register REGNUM should be omitted from "info registers"
+   display.  */
+
+int
+register_hidesome (int regnum)
+{
+  return TYPE_CODE (REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT;
+}
+
+/* Return whether register REGNUM should be omitted from "info registers" and
+   "info all-registers" display.  */
+
+int
+register_hideall (int regnum)
+{
+  return 0;
+}
+
+/* Return whether register REGNUM is read-only.  */
+
+int
+register_rdonly (int regnum)
+{
+  return 0;
+}
+
+/* Return whether side-effects result from reading register REGNUM.  */
+
+int
+register_reffect (int regnum)
+{
+  return 0;
+}
+
+/* Return whether register REGNUM is a memory-only register.  */
+
+int
+register_memonly (int regnum)
+{
+  return 0;
+}
+
+/* Try to fetch register REGNUM's value from FRAME into RAWBUF.  Return 1 on
+   success, 0 on failure if a future attempt might succeed, -1 otherwise.  */
+
+int
+fetch_frame_register (struct frame_info *frame, int regnum, char *rawbuf)
+{
+  return !read_relative_register_raw_bytes_for_frame (regnum, rawbuf, frame);
+}
+
 /* Fetch register REGNUM into the cache.  */
 
 static void
 fetch_register (int regnum)
 {
-  if (real_register (regnum))
-    target_fetch_registers (regnum);
-  else if (pseudo_register (regnum))
+  if (PSEUDO_REGISTER (regnum))
     FETCH_PSEUDO_REGISTER (regnum);
+  else if (REAL_REGISTER (regnum))
+    target_fetch_registers (regnum);
+  else
+    internal_error (__FILE__, __LINE__,
+		    "fetch_register: register %d is neither real nor pseudo",
+		    regnum);
 }
 
 /* Write register REGNUM cached value to the target.  */
@@ -131,10 +213,17 @@ fetch_register (int regnum)
 static void
 store_register (int regnum)
 {
-  if (real_register (regnum))
-    target_store_registers (regnum);
-  else if (pseudo_register (regnum))
+  if (REGISTER_RDONLY (regnum))
+    error ("Register %d is read-only.", regnum);
+
+  if (PSEUDO_REGISTER (regnum))
     STORE_PSEUDO_REGISTER (regnum);
+  else if (REAL_REGISTER (regnum))
+    target_store_registers (regnum);
+  else
+    internal_error (__FILE__, __LINE__,
+		    "store_register: register %d is neither real nor pseudo",
+		    regnum);
 }
 
 /* FIND_SAVED_REGISTER ()
@@ -296,7 +385,7 @@ get_saved_register (char *raw_buffer,
 /* FIXME: This function increases the confusion between FP_REGNUM
    and the virtual/pseudo-frame pointer.  */
 
-static int
+int
 read_relative_register_raw_bytes_for_frame (int regnum,
 					    char *myaddr,
 					    struct frame_info *frame)
@@ -314,7 +403,7 @@ read_relative_register_raw_bytes_for_fra
   get_saved_register (myaddr, &optim, (CORE_ADDR *) NULL, frame,
 		      regnum, (enum lval_type *) NULL);
 
-  if (register_cached (regnum) < 0)
+  if (REGISTER_CACHED (regnum) < 0)
     return 1;			/* register value not available */
 
   return optim;
@@ -362,12 +451,12 @@ registers_changed (void)
   alloca (0);
 
   for (i = 0; i < ARCH_NUM_REGS; i++)
-    set_register_cached (i, 0);
+    SET_REGISTER_CACHED (i, 0);
 
   /* Assume that if all the hardware regs have changed, 
      then so have the pseudo-registers.  */
   for (i = NUM_REGS; i < NUM_REGS + NUM_PSEUDO_REGS; i++)
-    set_register_cached (i, 0);
+    SET_REGISTER_CACHED (i, 0);
 
   if (registers_changed_hook)
     registers_changed_hook ();
@@ -384,7 +473,7 @@ registers_fetched (void)
   int i;
 
   for (i = 0; i < ARCH_NUM_REGS; i++)
-    set_register_cached (i, 1);
+    SET_REGISTER_CACHED (i, 1);
   /* Do not assume that the pseudo-regs have also been fetched.
      Fetching all real regs might not account for all pseudo-regs.  */
 }
@@ -429,7 +518,7 @@ read_register_bytes (int inregbyte, char
     {
       int regstart, regend;
 
-      if (register_cached (regnum))
+      if (REGISTER_CACHED (regnum))
 	continue;
 
       if (REGISTER_NAME (regnum) == NULL || *REGISTER_NAME (regnum) == '\0')
@@ -446,7 +535,7 @@ read_register_bytes (int inregbyte, char
          Update it from the target.  */
       fetch_register (regnum);
 
-      if (!register_cached (regnum))
+      if (!REGISTER_CACHED (regnum))
 	{
 	  /* Sometimes pseudoregs are never marked valid, so that they 
 	     will be fetched every time (it can be complicated to know
@@ -458,7 +547,7 @@ read_register_bytes (int inregbyte, char
     }
 
   if (myaddr != NULL)
-    memcpy (myaddr, register_buffer (-1) + inregbyte, inlen);
+    memcpy (myaddr, REGISTER_BUFFER (-1) + inregbyte, inlen);
 }
 
 /* Read register REGNUM into memory at MYADDR, which must be large
@@ -475,10 +564,10 @@ read_register_gen (int regnum, char *mya
       registers_pid = inferior_pid;
     }
 
-  if (!register_cached (regnum))
+  if (!REGISTER_CACHED (regnum))
     fetch_register (regnum);
 
-  memcpy (myaddr, register_buffer (regnum),
+  memcpy (myaddr, REGISTER_BUFFER (regnum),
 	  REGISTER_RAW_SIZE (regnum));
 }
 
@@ -511,16 +600,16 @@ write_register_gen (int regnum, char *my
   /* If we have a valid copy of the register, and new value == old value,
      then don't bother doing the actual store. */
 
-  if (register_cached (regnum)
-      && memcmp (register_buffer (regnum), myaddr, size) == 0)
+  if (REGISTER_CACHED (regnum)
+      && memcmp (REGISTER_BUFFER (regnum), myaddr, size) == 0)
     return;
 
-  if (real_register (regnum))
+  if (REAL_REGISTER (regnum))
     target_prepare_to_store ();
 
-  memcpy (register_buffer (regnum), myaddr, size);
+  memcpy (REGISTER_BUFFER (regnum), myaddr, size);
 
-  set_register_cached (regnum, 1);
+  SET_REGISTER_CACHED (regnum, 1);
   store_register (regnum);
 }
 
@@ -568,7 +657,7 @@ write_register_bytes (int myregstart, ch
 	     Update it from the target before scribbling on it.  */
 	  read_register_gen (regnum, regbuf);
 
-	  memcpy (registers + overlapstart,
+	  memcpy (REGISTER_BUFFER (-1) + overlapstart,
 		  myaddr + (overlapstart - myregstart),
 		  overlapend - overlapstart);
 
@@ -589,10 +678,10 @@ read_register (int regnum)
       registers_pid = inferior_pid;
     }
 
-  if (!register_cached (regnum))
+  if (!REGISTER_CACHED (regnum))
     fetch_register (regnum);
 
-  return (extract_unsigned_integer (register_buffer (regnum),
+  return (extract_unsigned_integer (REGISTER_BUFFER (regnum),
 				    REGISTER_RAW_SIZE (regnum)));
 }
 
@@ -627,10 +716,10 @@ read_signed_register (int regnum)
       registers_pid = inferior_pid;
     }
 
-  if (!register_cached (regnum))
+  if (!REGISTER_CACHED (regnum))
     fetch_register (regnum);
 
-  return (extract_signed_integer (register_buffer (regnum),
+  return (extract_signed_integer (REGISTER_BUFFER (regnum),
 				  REGISTER_RAW_SIZE (regnum)));
 }
 
@@ -680,16 +769,16 @@ write_register (int regnum, LONGEST val)
   /* If we have a valid copy of the register, and new value == old value,
      then don't bother doing the actual store. */
 
-  if (register_cached (regnum)
-      && memcmp (register_buffer (regnum), buf, size) == 0)
+  if (REGISTER_CACHED (regnum)
+      && memcmp (REGISTER_BUFFER (regnum), buf, size) == 0)
     return;
 
-  if (real_register (regnum))
+  if (REAL_REGISTER (regnum))
     target_prepare_to_store ();
 
-  memcpy (register_buffer (regnum), buf, size);
+  memcpy (REGISTER_BUFFER (regnum), buf, size);
 
-  set_register_cached (regnum, 1);
+  SET_REGISTER_CACHED (regnum, 1);
   store_register (regnum);
 }
 
@@ -734,19 +823,19 @@ supply_register (int regnum, char *val)
     }
 #endif
 
-  set_register_cached (regnum, 1);
+  SET_REGISTER_CACHED (regnum, 1);
   if (val)
-    memcpy (register_buffer (regnum), val, 
+    memcpy (REGISTER_BUFFER (regnum), val, 
 	    REGISTER_RAW_SIZE (regnum));
   else
-    memset (register_buffer (regnum), '\000', 
+    memset (REGISTER_BUFFER (regnum), '\000', 
 	    REGISTER_RAW_SIZE (regnum));
 
   /* On some architectures, e.g. HPPA, there are a few stray bits in
      some registers, that the rest of the code would like to ignore.  */
 
 #ifdef CLEAN_UP_REGISTER_VALUE
-  CLEAN_UP_REGISTER_VALUE (regnum, register_buffer (regnum));
+  CLEAN_UP_REGISTER_VALUE (regnum, REGISTER_BUFFER (regnum));
 #endif
 }
 
@@ -934,10 +1023,14 @@ build_regcache (void)
   int sizeof_registers = REGISTER_BYTES + /* SLOP */ 256;
   int sizeof_register_valid = 
     (NUM_REGS + NUM_PSEUDO_REGS) * sizeof (*register_valid);
-  registers = xmalloc (sizeof_registers);
-  memset (registers, 0, sizeof_registers);
-  register_valid = xmalloc (sizeof_register_valid);
-  memset (register_valid, 0, sizeof_register_valid);
+
+  if (REGCACHE_MODULE_ACTIVE)
+    {
+      registers = xmalloc (sizeof_registers);
+      memset (registers, 0, sizeof_registers);
+      register_valid = xmalloc (sizeof_register_valid);
+      memset (register_valid, 0, sizeof_register_valid);
+    }
 }
 
 void
Index: gdb/regs.c
===================================================================
diff -up /dev/null gdb/regs.c
--- /dev/null	Sun Feb 12 03:29:56 1995
+++ gdb/regs.c	Tue Feb 13 23:37:16 2001
@@ -0,0 +1,1728 @@
+/* Target register definition interface for GDB, the GNU debugger.
+   Copyright 2001 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 <stdlib.h>
+
+#include "defs.h"
+#include "inferior.h"
+#include "arch-utils.h"
+#include "gdbcore.h"
+#include "symfile.h"
+#include "regs.h"
+
+/* Expand to internal_error()'s required initial arguments.  */
+
+#define _ __FILE__, __LINE__,
+
+/* Register flag bits used internally by this module.  */
+
+enum
+  {
+    REGS_MAPPED = 0x80000000,	/* register is memory-mapped */
+    REGS_PSEUDO = 0x40000000,	/* pseudo register */
+    REGS_REAL = 0x20000000	/* real register */
+  };
+
+/* Register value type.  */
+
+enum valtype
+  {
+    val_nofetch,		/* not fetchable */
+    val_fetch,			/* fetchable (innermost frame if real
+				   register, any frame if pseudo register) */
+    val_real,			/* real register value stored in
+				   regval.rawbuf (innermost frame) */
+    val_pseudo,			/* pseudo register value stored in
+				   regval.rawbuf (any frame) */
+    val_real2,			/* reference to real register (non-innermost
+				   frame) */
+    val_memory,			/* fetchable from memory (non-innermost
+				   frame) */
+    val_calc			/* calculated value stored in regval.rawbuf
+				   (non-innermost frame) */
+  };
+
+/* Register value information.  */
+
+struct regval
+  {
+    enum valtype type;		/* value type */
+    CORE_ADDR addr;		/* memory address if .type is val_memory */
+    char *rawbuf;		/* value if .type is val_calc, val_real, or
+				   val_pseudo */
+  };
+
+/* Per-register information.  */
+
+struct reg
+  {
+    int tnum;			/* target register number (must never
+				   change) */
+    char *name;			/* register name, may be null */
+    int dnum;			/* debug info register number */
+    int size;			/* raw size, in bytes */
+    struct type **type;		/* virtual data type */
+    CORE_ADDR mem;		/* if .flags & REGS_MAPPED, register's memory
+				   location */
+    unsigned int flags;		/* REGS_* bitmask */
+    regs_rpseudo_ftype rpseudo;	/* if non-null, pseudo register read
+				   callback */
+    regs_wpseudo_ftype wpseudo;	/* if non-null, pseudo register write
+				   callback */
+    void *pseudo_data;		/* opaque data passed to .rpseudo and
+				   .wpseudo */
+    int *parents;		/* if non-null, -1-terminated list of
+				   registers on which this register's value
+				   depends */
+    struct reg **children;	/* if non-null, null-terminated list of
+				   registers whose values depend on this
+				   register's */
+    int offset;			/* byte offset in raw register buffer */
+    struct regval val;		/* information about this register's value */
+  };
+
+/* Per-architecture information for internal use by this module.  */
+
+struct inf
+  {
+    int nregs;			/* total number of registers */
+    int nnregs;			/* number of named registers */
+    int nmregs;			/* number of memory-mapped registers */
+    struct reg *regs;		/* per-register information */
+    struct reg **tnums;		/* .regs pointers sorted by number */
+    struct reg **names;		/* .regs pointers sorted by name */
+    struct reg **mems;		/* .regs pointers sorted by memory location */
+    char *cache;		/* storage for all raw register values */
+    int cachesize;		/* size of .cache */
+    int rawmax;			/* largest possible raw register size */
+    char *namebuf;		/* for storing any register name */
+    int namemax;		/* longest string that fits in .namebuf */
+    regs_caller_ftype
+	caller_regs;		/* callback for locating caller's regs */
+    regs_remap_ftype remap;	/* if non-null, callback to change the
+				   register memory map */
+    void *remap_data;		/* opaque data passed to .remap */
+  };
+
+/* Initialization context returned by regs_init_start().  */
+
+struct regs_init_context
+  {
+    struct gdbarch *gdbarch;
+    struct inf *inf;
+    int virtmax;
+    int max_real_tnum;
+    int npseudos;
+    int regssz;
+  };
+
+/* Memory region search key used by find_mem().  */
+
+struct memfind
+  {
+    CORE_ADDR addr;		/* start of memory region */
+    int len;			/* length of region */
+  };
+
+/* Identifier returned by register_gdbarch_data().  */
+
+static struct gdbarch_data *inf_id;
+
+/* Back end to find_*(): return the <register> in LEN-element ARRAY for
+   which CMP (KEY, <register>) returns 0, or null if no such register exists.  */
+
+static struct reg *
+find (const void *key, struct reg **array, int len,
+      int (*cmp)(const void *, const void *))
+{
+  struct reg **found;
+
+  found = bsearch (key, array, len, sizeof (struct reg *), cmp);
+  return found ? *found : NULL;
+}
+
+/* bsearch() comparison function: return -1, 0, or 1 according to whether
+   register number *TNUMP is less than, equal to, or greater than register
+   *REGP's number.  */
+
+static int
+find_tnum_cmp (const void *tnump, const void *regp)
+{
+  int tnum;
+  struct reg *reg;
+
+  tnum = *(int *) tnump;
+  reg = *(struct reg **) regp;
+  return tnum < reg->tnum ? -1 : tnum > reg->tnum;
+}
+
+/* bsearch() comparison function: return -1, 0, or 1 according to whether
+   register NAME is lexically less than, equal to, or greater than register
+   *REGP's name.  */
+
+static int
+find_name_cmp (const void *name, const void *regp)
+{
+  struct reg *reg;
+
+  reg = *(struct reg **) regp;
+  return strcasecmp (name, reg->name);
+}
+
+/* bsearch() comparison function: return -1, 0, or 1 according to whether
+   memory region *MEMP precedes, overlaps, or follows register *REGP's memory
+   location.  */
+
+static int
+find_mem_cmp (const void *memp, const void *regp)
+{
+  struct memfind *mem;
+  struct reg *reg;
+
+  mem = (struct memfind *) memp;
+  reg = *(struct reg **) regp;
+  return mem->addr + mem->len <= reg->mem ? -1
+    : mem->addr >= reg->mem + reg->size;
+}
+
+/* qsort() comparison function: return -1, 0, or 1 according to whether the
+   name of register **REG1P is lexically less than, equal to, or greater than
+   the name of register **REG2P.  */
+
+static int
+init_name_cmp (const void *reg1p, const void *reg2p)
+{
+  struct reg *reg1, *reg2;
+
+  reg1 = *(struct reg **) reg1p;
+  reg2 = *(struct reg **) reg2p;
+  return strcasecmp (reg1->name, reg2->name);
+}
+
+/* qsort() comparison function: return -1, 0, or 1 according to whether the
+   number of register **REG1P is less than, equal to, or greater than the
+   number of register **REG2P.  */
+
+static int
+init_tnum_cmp (const void *reg1p, const void *reg2p)
+{
+  struct reg *reg1, *reg2;
+
+  reg1 = *(struct reg **) reg1p;
+  reg2 = *(struct reg **) reg2p;
+  return reg1->tnum < reg2->tnum ? -1 : reg1->tnum > reg2->tnum;
+}
+
+/* qsort() comparison function: return -1, 0, or 1 according to whether the
+   memory location of register **REG1P is less than, equal to, or greater than
+   the memory location of register **REG2P.  */
+
+static int
+init_mem_cmp (const void *reg1p, const void *reg2p)
+{
+  struct reg *reg1, *reg2;
+
+  reg1 = *(struct reg **) reg1p;
+  reg2 = *(struct reg **) reg2p;
+  return reg1->mem < reg2->mem ? -1 : reg1->mem > reg2->mem;
+}
+
+/* qsort() comparison function: return -1, 0, or 1 according to whether
+   integer *INT1P is less than, equal to, or greater than integer *INT2P.  */
+
+static int
+intcmp (const void *int1p, const void *int2p)
+{
+  int int1, int2;
+
+  int1 = *(int *) int1p;
+  int2 = *(int *) int2p;
+  return int1 < int2 ? -1 : int1 > int2;
+}
+
+/* Update the register memory map.  */
+
+static void
+update_mem (struct inf *inf)
+{
+  if (inf->remap && inf->remap (inf->remap_data))
+    qsort (inf->mems, inf->nmregs, sizeof (struct reg *), init_mem_cmp);
+}
+
+/* If a register has target number TNUM, return that register.  Otherwise, if
+   !CALLER, return null, else throw an error message identifying CALLER.  */
+
+static struct reg *
+find_tnum (int tnum, char *caller)
+{
+  struct inf *inf;
+  struct reg *reg;
+
+  inf = gdbarch_data (inf_id);
+  reg = find (&tnum, inf->tnums, inf->nregs, find_tnum_cmp);
+  if (reg)
+    return reg;
+  if (caller)
+    internal_error (_"%s: invalid register target number %d", caller, tnum);
+  return NULL;
+}
+
+/* If a register overlaps the LEN-byte memory region starting at ADDR, return
+   a pointer to that register's entry in the memory lookup array, else return
+   null.  */
+
+static struct reg **
+find_mem (CORE_ADDR addr, int len)
+{
+  struct reg **found;
+  struct memfind mem;
+  struct inf *inf;
+
+  inf = gdbarch_data (inf_id);
+  if (!inf->nmregs)
+    return NULL;
+
+  update_mem (inf);
+
+  mem.addr = addr;
+  mem.len = len;
+  return bsearch (&mem, inf->mems, inf->nmregs, sizeof (struct reg *),
+		  find_mem_cmp);
+}
+
+/* Return the valtype corresponding to integer VALIDITY, treating VALID as
+   corresponding to 1.  */
+
+static enum valtype
+int_valtype (int validity, enum valtype valid)
+{
+  if (validity < 0)
+    return val_nofetch;
+  if (validity == 0)
+    return val_fetch;
+  return valid;
+}
+
+/* Set TNUM's cache state in the innermost frame to STATE.  */
+
+static void
+set_valid (struct reg *reg, int state)
+{
+  struct reg **child;
+  struct regval *val;
+
+  reg->val.type = int_valtype (state, reg->flags & REGS_PSEUDO
+			       ? val_pseudo : val_real);
+
+  /* Invalidate dependent registers.  */
+  if (reg->children)
+    for (child = reg->children; *child; child++)
+      (*child)->val.type = val_fetch;
+}
+
+/* Try to fetch pseudo register REG's value in FRAME into VAL.  */
+
+static void
+fetch_pseudo (struct frame_info *frame, struct reg *reg,
+	      struct regval *val)
+{
+  int valid;
+  char *rawbuf;
+
+  if (!reg->rpseudo)
+    return;
+
+  rawbuf = (char *) alloca (MAX_REGISTER_RAW_SIZE);
+  valid = reg->rpseudo (frame, reg->tnum, reg->parents, reg->pseudo_data,
+			rawbuf);
+
+  val->type = int_valtype (valid, val_pseudo);
+  memcpy (val->rawbuf, rawbuf, reg->size);
+}
+
+/* Try to set pseudo register REG's value in FRAME to VAL.  */
+
+static void
+store_pseudo (struct frame_info *frame, struct reg *reg,
+	      struct regval *val)
+{
+  int valid;
+  char *rawbuf;
+
+  if (!reg->wpseudo)
+    return;
+
+  rawbuf = (char *) alloca (MAX_REGISTER_RAW_SIZE);
+  memcpy (rawbuf, val->rawbuf, reg->size);
+
+  valid = reg->wpseudo (frame, reg->tnum, reg->parents, reg->pseudo_data,
+			rawbuf);
+  val->type = int_valtype (valid, val_pseudo);
+}
+
+/* Return FRAME's caller's register information, retrieving it first if
+   necessary.  */
+
+static struct regval *
+caller_vals (struct frame_info *frame)
+{
+  struct inf *inf;
+  struct regval *vals, *vals_next, *val, *val2;
+  char *rawbufs, *dummybuf;
+  struct reg *reg2;
+  int i;
+
+  /* Don't retrieve twice.  */
+  if (frame->extra_info)
+    vals = (struct regval *) frame->extra_info;
+
+  else
+    {
+      /* Allocate space for the frame's register information.  */
+      inf = gdbarch_data (inf_id);
+      vals = frame_obstack_alloc (sizeof (struct regval) * inf->nregs);
+      frame->extra_info = (struct frame_extra_info *) vals;
+      rawbufs = frame_obstack_alloc (inf->cachesize);
+
+      if (frame->next)
+	vals_next = (struct regval *) frame->next->extra_info;
+      else
+	vals_next = NULL;
+
+      /* If FRAME is a generic dummy frame, copy its saved caller state.  */
+      if (!USE_GENERIC_DUMMY_FRAMES)
+	dummybuf = NULL;
+      else
+	{
+	  dummybuf = generic_find_dummy_frame (frame->pc, frame->frame);
+	  if (dummybuf)
+	    memcpy (rawbufs, dummybuf, inf->cachesize);
+	}
+
+      /* Initialize the caller's register state.  */
+      for (i = 0; i < inf->nregs; i++)
+	{
+	  val = vals + i;
+	  reg2 = inf->regs + i;
+
+	  val->rawbuf = rawbufs;
+	  rawbufs += reg2->size;
+
+	  /* Pseudo registers should be regenerated in each frame.  */
+	  if (reg2->flags & REGS_PSEUDO)
+	    val->type = val_fetch;
+
+	  /* Dummy frame caller's registers are saved by value.  */
+	  else if (dummybuf)
+	    val->type = val_calc;
+
+	  /* Initialize the caller's real register state to that of FRAME's
+	     so that inf->caller_regs() can update it.  */
+
+	  /* Innermost frame's real registers are the current registers.  */
+	  else if (!vals_next)
+	    val->type = val_real2;
+
+	  /* Non-innermost frame's real registers are in vals_next.  */
+	  else
+	    {
+	      val2 = vals_next + i;
+	      val->type = val2->type;
+	      if (val->type == val_memory)
+		val->addr = val2->addr;
+	      else if (val->type == val_calc)
+		memcpy (val->rawbuf, val2->rawbuf, reg2->size);
+	    }
+	}
+
+      /* Target does the real work of converting FRAME's register state to
+         its caller's.  Maybe someday a generic emulator will do this.  */
+      if (!dummybuf)
+	inf->caller_regs (frame);
+    }
+
+  return vals;
+}
+
+/* Return register REG's value information in FRAME's caller, retrieving
+   FRAME's caller information first if necessary.  */
+
+static struct regval *
+caller_val (struct frame_info *frame, struct reg *reg)
+{
+  struct inf *inf;
+  struct regval *vals;
+
+  inf = gdbarch_data (inf_id);
+  vals = caller_vals (frame);
+
+  return vals + (reg - inf->regs);
+}
+
+/* Return register REG's value information in FRAME.  */
+
+static struct regval *
+frame_val (struct frame_info *frame, struct reg *reg)
+{
+  if (!frame || !frame->next)
+    return &reg->val;
+  return caller_val (frame->next, reg);
+}
+
+/* Try to fetch register REG's value from FRAME into RAWBUF.  Return 1 on
+   success, 0 on failure if a future attempt might succeed, -1 otherwise.  */
+
+static int
+fetch_frame (struct frame_info *frame, struct reg *reg, char *rawbuf)
+{
+  struct regval *val;
+
+  /* Locate the register's value info.  */
+  val = frame_val (frame, reg);
+  if (val->type == val_real2)
+    val = frame_val (NULL, reg);
+
+  /* Update the value info.  */
+  if (val->type == val_fetch)
+    {
+      if (reg->flags & REGS_PSEUDO)
+	fetch_pseudo (frame, reg, val);
+      else
+	/* Only possible in the innermost frame.  */
+	target_fetch_registers (reg->tnum);
+    }
+
+  /* Copy the value to RAWBUF and return.  */
+  switch (val->type)
+    {
+    case val_nofetch:
+      return -1;
+    case val_fetch:
+      return 0;
+    case val_calc:
+    case val_pseudo:
+    case val_real:
+      memcpy (rawbuf, val->rawbuf, reg->size);
+      return 1;
+    case val_memory:
+      return !target_read_memory (val->addr, rawbuf, reg->size);
+    case val_real2:
+    default:
+      internal_error (_"fetch_frame: impossible value type");
+      return -1;
+    }
+}
+
+/* Try to fetch register TNUM's value from FRAME into RAWBUF.  Return 1 on
+   success, 0 on failure if a future attempt might succeed, -1 otherwise.  */
+
+int
+regs_fetch_frame (struct frame_info *frame, int tnum, char *rawbuf)
+{
+  struct reg *reg;
+
+  reg = find_tnum (tnum, "regs_fetch_frame");
+  return fetch_frame (frame, reg, rawbuf);
+}
+
+/* Try to store RAWBUF as register REG's value in FRAME.  Return success.  */
+
+static int
+store_frame (struct frame_info *frame, struct reg *reg, char *rawbuf)
+{
+  struct regval *val;
+
+  /* Locate the register's value info.  */
+  val = frame_val (frame, reg);
+
+  /* Handle memory and unwritable cases.  */
+  switch (val->type)
+    {
+    case val_memory:
+      return !target_write_memory (val->addr, rawbuf, reg->size);
+    case val_calc:
+    case val_real2:
+    case val_nofetch:
+      return 0;
+    default:
+      break;
+    }
+
+  /* It's a real register in the innermost frame or a pseudo register in any
+     frame.  Attempt the store.  */
+  val->type = val_fetch;
+  memcpy (val->rawbuf, rawbuf, reg->size);
+
+  if (reg->flags & REGS_PSEUDO)
+    store_pseudo (frame, reg, val);
+  else
+    {
+      /* Will return nonlocally if there were problems.  */
+      target_store_registers (reg->tnum);
+      val->type = val_real;
+    }
+
+  return val->type == val_pseudo || val->type == val_real;
+}
+
+/* Try to store RAWBUF as register TNUM's value in FRAME.  Return
+   success.  */
+
+int
+regs_store_frame (struct frame_info *frame, int tnum, char *rawbuf)
+{
+  struct reg *reg;
+
+  reg = find_tnum (tnum, "regs_store_frame");
+  return store_frame (frame, reg, rawbuf);
+}
+
+/* Return the value of register TNUM in FRAME.  */
+
+ULONGEST
+regs_get_frame (struct frame_info *frame, int tnum)
+{
+  struct inf *inf;
+  struct reg *reg;
+  char *rawbuf;
+
+  inf = gdbarch_data (inf_id);
+  reg = find_tnum (tnum, "get_frame");
+  rawbuf = (char *) alloca (inf->rawmax);
+
+  if (fetch_frame (frame, reg, rawbuf) <= 0)
+    return 0;
+  return extract_unsigned_integer (rawbuf, reg->size);
+}
+
+/* Return the value of register TNUM in FRAME's caller.  */
+
+ULONGEST
+regs_get_caller (struct frame_info *frame, int tnum)
+{
+  struct frame_info prev_frame;
+
+  prev_frame.next = frame;
+  return regs_get_frame (&prev_frame, tnum);
+}
+
+/* Record the fact that register TNUM's value in FRAME's caller is:
+     - VALUE if LVAL is not_lval
+     - in memory location VALUE if LVAL is lval_memory
+     - in register TNUM if LVAL is lval_register  */
+
+void
+regs_set_caller (struct frame_info *frame, int tnum,
+		 enum lval_type lval, ULONGEST value)
+{
+  struct reg *reg;
+  struct regval *val;
+
+  reg = find_tnum (tnum, "regs_set_caller");
+  val = caller_val (frame, reg);
+
+  switch (lval)
+    {
+    case lval_memory:
+      val->type = val_memory;
+      val->addr = value;
+      break;
+    case lval_register:
+      val->type = val_real2;
+      break;
+    case not_lval:
+      val->type = val_calc;
+      store_unsigned_integer (val->rawbuf, reg->size, value);
+      break;
+    default:
+      internal_error (_"regs_set_caller: illegal lval");
+      break;
+    }
+}
+
+/* Copy register TNUM1's caller information in FRAME to register
+   TNUM2's.  */
+
+void
+regs_copy_caller (struct frame_info *frame, int tnum1, int tnum2)
+{
+  struct reg *reg1, *reg2;
+  struct regval *val1, *val2;
+
+  reg1 = find_tnum (tnum1, "regs_copy_caller");
+  reg2 = find_tnum (tnum2, "regs_copy_caller");
+
+  val1 = caller_val (frame, reg1);
+  val2 = caller_val (frame, reg2);
+
+  val2->type = val1->type;
+  switch (val1->type)
+    {
+    case val_memory:
+      val2->addr = val1->addr;
+      break;
+    case val_real2:
+      if (fetch_frame (frame, reg1, val2->rawbuf) <= 0)
+	val2->type = val_nofetch;
+      else
+	val2->type = val_calc;
+      break;
+    case val_calc:
+      memcpy (val2->rawbuf, val1->rawbuf, reg2->size);
+      break;
+    default:
+      break;
+    }
+}
+
+/* Set each memory-mapped register's memory location to ADJUST (<regnum>,
+   <mem>, DATA) where <regnum> and <mem> are the register's target number and
+   current memory location, respectively.  */
+
+void
+regs_remap (CORE_ADDR (*adjust) (int, CORE_ADDR, void *), void *data)
+{
+  struct inf *inf;
+  struct reg *reg;
+  int i;
+
+  inf = gdbarch_data (inf_id);
+
+  for (i = 0; i < inf->nmregs; i++)
+    {
+      reg = inf->mems[i];
+      reg->mem = adjust (reg->tnum, reg->mem, data);
+    }
+}
+
+/* Pseudo-register callback to read an alias register.  */
+
+int
+regs_rpseudo_alias (struct frame_info *frame, int tnum, int *parents,
+		    void *data, char *rawbuf)
+{
+  return regs_fetch_frame (frame, *parents, rawbuf);
+}
+
+/* Pseudo-register callback to write an alias register.  */
+
+int
+regs_wpseudo_alias (struct frame_info *frame, int tnum, int *parents,
+		    void *data, char *rawbuf)
+{
+  return regs_store_frame (frame, *parents, rawbuf);
+}
+
+/* Pseudo-register callback to read a memory register.  */
+
+int
+regs_rpseudo_mem (struct frame_info *frame, int tnum, int *parents,
+		  void *data, char *rawbuf)
+{
+  struct reg *reg;
+
+  reg = find_tnum (tnum, "regs_rpseudo_mem");
+  update_mem (gdbarch_data (inf_id));
+  return !target_read_memory (reg->mem, rawbuf, reg->size);
+}
+
+/* Pseudo-register callback to write an alias register.  */
+
+int
+regs_wpseudo_mem (struct frame_info *frame, int tnum, int *parents, void
+		  *data, char *rawbuf)
+{
+  struct reg *reg;
+
+  reg = find_tnum (tnum, "regs_store_memory_register");
+  update_mem (gdbarch_data (inf_id));
+  return !target_write_memory (reg->mem, rawbuf, reg->size);
+}
+
+/* Pseudo-register callback to read a vector register.  */
+
+int
+regs_rpseudo_vec (struct frame_info *frame, int tnum, int *parents,
+		  void *data, char *rawbuf)
+{
+  int *parent, size;
+  struct reg *reg;
+
+  reg = find_tnum (tnum, "regs_rpseudo_vec");
+  size = TYPE_LENGTH (TYPE_TARGET_TYPE (*reg->type));
+
+  for (parent = parents; *parent >= 0; parent++)
+    {
+      if (regs_fetch_frame (frame, *parent, rawbuf) <= 0)
+	return 0;
+      rawbuf += size;
+    }
+  return 1;
+}
+
+/* Pseudo-register callback to write a vector register.  */
+
+int
+regs_wpseudo_vec (struct frame_info *frame, int tnum, int *parents,
+		  void *data, char *rawbuf)
+{
+  int *parent, size;
+  struct reg *reg;
+
+  reg = find_tnum (tnum, "regs_wpseudo_vec");
+  size = TYPE_LENGTH (TYPE_TARGET_TYPE (*reg->type));
+
+  for (parent = parents; *parent >= 0; parent++)
+    {
+      if (!regs_store_frame (frame, *parent, rawbuf))
+	return 0;
+      rawbuf += size;
+    }
+  return 1;
+}
+
+/* Pseudo-register callback to sum all parent registers.  */
+
+int
+regs_rpseudo_sum (struct frame_info *frame, int tnum, int *parents,
+		  void *data, char *rawbuf)
+{
+  struct inf *inf;
+  struct reg *reg;
+  int *parent;
+  LONGEST sum;
+
+  inf = gdbarch_data (inf_id);
+
+  for (sum = 0, parent = parents; *parent >= 0; parent++)
+    {
+      reg = find_tnum (*parent, "regs_rpseudo_sum");
+      if (fetch_frame (frame, reg, rawbuf) <= 0)
+	return 0;
+      sum += extract_unsigned_integer (rawbuf, reg->size);
+    }
+
+  reg = find_tnum (tnum, "regs_rpseudo_sum");
+  store_unsigned_integer (rawbuf, reg->size, sum);
+  return 1;
+}
+
+/* Pseudo-register callback to store in the first parent register the result
+   of subtracting the second parent register from RAWBUF.  */
+
+int
+regs_wpseudo_sub (struct frame_info *frame, int tnum, int *parents,
+		  void *data, char *rawbuf)
+{
+  struct inf *inf;
+  struct reg *reg;
+  LONGEST diff;
+
+  inf = gdbarch_data (inf_id);
+  reg = find_tnum (tnum, "regs_wpseudo_sub");
+  diff = extract_unsigned_integer (rawbuf, reg->size);
+
+  reg = find_tnum (parents[1], "regs_wpseudo_sub");
+  if (fetch_frame (frame, reg, rawbuf) <= 0)
+    return 0;
+  diff -= extract_unsigned_integer (rawbuf, reg->size);
+
+  reg = find_tnum (parents[0], "regs_wpseudo_sub");
+  store_unsigned_integer (rawbuf, reg->size, diff);
+  return store_frame (frame, reg, rawbuf);
+}
+
+/* Retrieve information about register TNUM's value in FRAME.  Specifically:
+
+     - Store the raw value in RAW_BUFFER.
+
+     - Set *INVALIDP to whether the value can't be retrieved.
+
+     - If the current value in the register is correct for FRAME, store the
+       register's cache offset in ADDRP and set *LVALP to lval_register.
+
+     - If the value is saved in memory, store the memory address in ADDRP and
+       set *LVALP to lval_memory.
+
+     - If the value is calculated or unavailable, set *LVALP to lval_noval.
+  
+  Any or all of RAW_BUFFER, OPTIMIZEDP, ADDRP, and LVALP may be null.  */
+
+static void
+regs_get_saved_register (char *rawbuf, int *invalidp, CORE_ADDR *addrp,
+			 struct frame_info *frame, int tnum,
+			 enum lval_type *lvalp)
+{
+  struct reg *reg;
+  struct regval *val;
+  int invalid;
+  CORE_ADDR addr;
+  enum lval_type lval;
+
+  if (!target_has_registers)
+    error ("No registers.");
+
+  reg = find_tnum (tnum, "regs_get_saved_register");
+  val = frame_val (frame, reg);
+
+  /* Fetch the register's value if requested.  */
+  if (rawbuf)
+    invalid = fetch_frame (frame, reg, rawbuf) <= 0;
+  else
+    invalid = val->type == val_nofetch;
+
+  /* Infer other requested information.  */
+  switch (val->type)
+    {
+    case val_memory:
+      lval = lval_memory;
+      addr = val->addr;
+      break;
+    case val_real:
+    case val_pseudo:
+      lval = lval_register;
+      addr = reg->offset;
+      break;
+    default:
+      lval = not_lval;
+      addr = 0;
+      break;
+    }
+
+  /* Return other requested information.  */
+  if (invalidp)
+    *invalidp = invalid;
+  if (addrp)
+    *addrp = addr;
+  if (lvalp)
+    *lvalp = lval;
+}
+
+/* Initialize newly-created FRAME's register information.  */
+
+static void
+regs_init_extra_frame_info (int fromleaf, struct frame_info *frame)
+{
+  frame->extra_info = NULL;
+}
+
+/* Initialize FRAME->saved_regs.
+
+   This is only called by (a) generic get_saved_register callbacks, which this
+   module replaces, and (b) frame_info(), which can handle a null
+   FRAME->saved_regs.
+
+   FIXME: either change frame_info() to understand this module's saved
+   register layout or else instantiate FRAME->saved_regs here.  */
+
+static void
+regs_frame_init_saved_regs (struct frame_info *frame)
+{
+  return;
+}
+
+/* Pop the topmost frame from the stack, restoring all saved registers.  */
+
+static void
+regs_pop_frame (void)
+{
+  struct frame_info *frame, prev_frame;
+  struct inf *inf;
+  struct reg *reg;
+  struct regval *vals, *val;
+  char *rawbuf;
+  int i;
+
+  frame = get_current_frame ();
+
+  if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame))
+    generic_pop_dummy_frame ();
+  else
+    {
+      inf = gdbarch_data (inf_id);
+      vals = caller_vals (frame);
+      prev_frame.next = frame;
+      rawbuf = (char *) alloca (inf->rawmax);
+
+      /* Copy the caller's registers to the register cache.  */
+      for (i = 0; i < inf->nregs; i++)
+	{
+	  val = vals + i;
+	  if (val->type != val_calc && val->type != val_memory)
+	    continue;
+
+	  reg = inf->regs + i;
+	  if (fetch_frame (&prev_frame, reg, rawbuf) > 0)
+	    write_register_gen (reg->tnum, rawbuf);
+	}
+    }
+  flush_cached_frames ();
+}
+
+/* Return the PC saved in FRAME.  */
+
+static CORE_ADDR
+regs_frame_saved_pc (struct frame_info *frame)
+{
+  return regs_get_caller (frame, PC_REGNUM);
+}
+
+/* Return the FP saved in FRAME.  */
+
+static CORE_ADDR
+regs_frame_chain (struct frame_info *frame)
+{
+  return regs_get_caller (frame, SP_REGNUM);
+}
+
+/* Attempt to synchronize pseudo register TNUM's cached value with the
+   innermost frame's register state.  */
+
+static void
+regs_fetch_pseudo_register (int tnum)
+{
+  struct inf *inf;
+  struct reg *reg;
+
+  inf = gdbarch_data (inf_id);
+  reg = find_tnum (tnum, "regs_fetch_pseudo_register");
+
+  if (reg->val.type == val_fetch)
+    fetch_pseudo (NULL, reg, &reg->val);
+}
+
+/* Attempt to synchronize the innermost frame's register state with
+   pseudo register TNUM's cached value.  */
+
+static void
+regs_store_pseudo_register (int tnum)
+{
+  struct inf *inf;
+  struct reg *reg;
+
+  inf = gdbarch_data (inf_id);
+  reg = find_tnum (tnum, "regs_store_pseudo_register");
+
+  store_pseudo (NULL, reg, &reg->val);
+}
+
+/* Return the name of register number TNUM, or null if no such register
+   exists in the current architecture.  */
+
+static char *
+regs_register_name (int tnum)
+{
+  struct reg *reg;
+
+  reg = find_tnum (tnum, NULL);
+  if (!reg)
+    return NULL;
+  if (!reg->name)
+    return "";
+  return reg->name;
+}
+
+/* Return the offset within the raw register buffer of the first byte of space
+   for register TNUM.  */
+
+static int
+regs_register_byte (int tnum)
+{
+  struct reg *reg;
+
+  reg = find_tnum (tnum, "regs_register_byte");
+  return reg->offset;
+}
+
+/* Return the number of bytes of storage allocated in the raw register buffer
+   for register TNUM if that register is available, else return 0.  */
+
+static int
+regs_register_raw_size (int tnum)
+{
+  struct reg *reg;
+
+  reg = find_tnum (tnum, NULL);
+  if (!reg)
+    return 0;
+  return reg->size;
+}
+
+/* Return the type used for GDB's virtual representation of register TNUM.  */
+
+static struct type *
+regs_register_virtual_type (int tnum)
+{
+  struct reg *reg;
+
+  reg = find_tnum (tnum, "regs_register_virtual_type");
+  return *reg->type;
+}
+
+/* Return the number of bytes of storage needed for GDB's virtual
+   representation of register TNUM.  */
+
+static int
+regs_register_virtual_size (int tnum)
+{
+  return TYPE_LENGTH (regs_register_virtual_type (tnum));
+}
+
+/* Return the target number of the register with LEN-byte NAME, or -1 if no
+   such register exists.  */
+
+static int
+regs_register_name_tnum (char *name, int len)
+{
+  struct inf *inf;
+  struct reg *reg;
+
+  inf = gdbarch_data (inf_id);
+  if (len > inf->namemax)
+    return -1;
+
+  memcpy (inf->namebuf, name, len);
+  inf->namebuf[len] = '\0';
+  reg = find (inf->namebuf, inf->names, inf->nnregs, find_name_cmp);
+  return reg ? reg->tnum : -1;
+}
+
+/* Return >0 if register TNUM's value in the innermost frame is cached, 0 if
+   it's uncached but fetchable, and <0 if it's uncached and unfetchable.  */
+
+static int
+regs_register_cached (int tnum)
+{
+  struct reg *reg;
+
+  reg = find_tnum (tnum, "regs_register_cached");
+  switch (reg->val.type)
+    {
+    case val_nofetch:
+      return -1;
+    case val_fetch:
+      return 0;
+    default:
+      if (reg->flags & REGS_RTHRU)
+	return 0;
+      return 1;
+    }
+}
+
+/* Record that TNUM's value is cached if STATE is >0, uncached but
+   fetchable if STATE is 0, and uncached and unfetchable if STATE is <0.
+
+   This function must be called whenever a register's cached state changes,
+   including when updating a valid value with a new valid value.  */
+
+static void
+regs_set_register_cached (int tnum, int state)
+{
+  struct reg *reg;
+
+  reg = find_tnum (tnum, "regs_set_register_cached");
+  set_valid (reg, state);
+}
+
+/* If TNUM >= 0, return a pointer to register TNUM's cache buffer area,
+   else return a pointer to the start of the cache buffer.  */
+
+static char *
+regs_register_buffer (int tnum)
+{
+  struct reg *reg;
+  struct inf *inf;
+
+  inf = gdbarch_data (inf_id);
+  if (tnum < 0)
+    return inf->cache;
+  else
+    {
+      reg = find_tnum (tnum, "regs_register_buffer");
+      return reg->val.rawbuf;
+    }
+}
+
+/* Return whether register TNUM is a real (not pseudo) register.  */
+
+static int
+regs_real_register (int tnum)
+{
+  struct reg *reg;
+
+  reg = find_tnum (tnum, NULL);
+  return reg && reg->flags & REGS_REAL;
+}
+
+/* Return whether register TNUM is a pseudo register.  */
+
+static int
+regs_pseudo_register (int tnum)
+{
+  struct reg *reg;
+
+  reg = find_tnum (tnum, NULL);
+  return reg && reg->flags & REGS_PSEUDO;
+}
+
+/* Return the target number of the first register that "info registers" and
+   "info all-registers" should consider for display.  */
+
+static int
+regs_register_info_first (void)
+{
+  struct inf *inf;
+
+  inf = gdbarch_data (inf_id);
+  if (!inf->nregs)
+    return -1;
+  return inf->regs[0].tnum;
+}
+
+/* Return the target number of the register that "info registers" and "info
+   all-registers" should consider for display after register TNUM.  If no
+   registers should be displayed after register TNUM, return -1.  */
+
+static int
+regs_register_info_next (int tnum)
+{
+  struct inf *inf;
+  struct reg *reg;
+
+  inf = gdbarch_data (inf_id);
+  reg = find_tnum (tnum, "regs_register_info_next");
+  if (++reg - inf->regs == inf->nregs)
+    return -1;
+  return reg->tnum;
+}
+
+/* Return the target number of the register mapped to memory ADDR, or -1 if no
+   such register exists.  */
+
+static int
+regs_register_addr_tnum (CORE_ADDR addr)
+{
+  struct reg *reg, **found;
+  struct memfind mem;
+
+  found = find_mem (addr, 1);
+  if (!found)
+    return -1;
+
+  reg = *found;
+  if (reg->mem != addr)
+    return -1;
+
+  return reg->tnum;
+}
+
+/* Invalidate any memory-mapped registers that the LEN-byte target memory
+   region starting at ADDR overlaps.  This function should be called whenever
+   target memory is written.  */
+
+static void
+regs_register_write_memory (CORE_ADDR addr, int len)
+{
+  struct reg *reg, **found;
+  struct memfind mem;
+  struct inf *inf;
+
+  inf = gdbarch_data (inf_id);
+  if (!inf)
+    return;
+
+  found = find_mem (addr, len);
+  if (!found)
+    return;
+
+  /* The region may overlap more than one register.  Find the overlapped
+     register nearest the start of the region, then invalidate registers
+     upward from there.  */
+
+  for (; found > inf->mems; found--)
+    {
+      reg = found[-1];
+      if (reg->mem + reg->size <= addr)
+	break;
+    }
+
+  for (; found < inf->mems + inf->nmregs; found++)
+    {
+      reg = *found;
+      if (reg->mem >= addr + len)
+	break;
+      set_valid (reg, 0);
+    }
+}
+
+/* Return whether register TNUM's FLAGS is set.  */
+
+static int
+regs_register_flag (int tnum, int flag)
+{
+  struct reg *reg;
+
+  reg = find_tnum (tnum, "regs_register_flag");
+  return reg->flags & flag;
+}
+
+/* Return whether register TNUM should be omitted from "info registers"
+   display.  */
+
+static int
+regs_register_hidesome (int tnum)
+{
+  return regs_register_flag (tnum, REGS_HIDESOME);
+}
+
+/* Return whether register TNUM should be omitted from "info registers" and
+   "info all-registers" display.  */
+
+static int
+regs_register_hideall (int tnum)
+{
+  return regs_register_flag (tnum, REGS_HIDEALL);
+}
+
+/* Return whether register TNUM is read-only.  */
+
+static int
+regs_register_rdonly (int tnum)
+{
+  return regs_register_flag (tnum, REGS_RDONLY);
+}
+
+/* Return whether side-effects result from reading register TNUM.  */
+
+static int
+regs_register_reffect (int tnum)
+{
+  return regs_register_flag (tnum, REGS_REFFECT);
+}
+
+/* Initialize INF's register lookup mechanisms.  */
+
+static void
+init_lookups (struct inf *inf)
+{
+  struct reg *reg;
+  int i, j, k;
+
+  inf->tnums = xmalloc (sizeof (struct reg *) * inf->nregs);
+
+  if (inf->nnregs)
+    inf->names = xmalloc (sizeof (struct reg *) * inf->nnregs);
+  else
+    inf->names = NULL;
+
+  if (inf->nmregs)
+    inf->mems = xmalloc (sizeof (struct reg *) * inf->nmregs);
+  else
+    inf->mems = NULL;
+
+  for (i = j = k = 0; i < inf->nregs; i++)
+    {
+      reg = inf->regs + i;
+      inf->tnums[i] = reg;
+      if (reg->name)
+	inf->names[j++] = reg;
+      if (reg->flags & REGS_MAPPED)
+	inf->mems[k++] = reg;
+    }
+
+  qsort (inf->tnums, inf->nregs, sizeof (struct reg *), init_tnum_cmp);
+  qsort (inf->names, inf->nnregs, sizeof (struct reg *), init_name_cmp);
+  qsort (inf->mems, inf->nmregs, sizeof (struct reg *), init_mem_cmp);
+
+  inf->namebuf = xmalloc (inf->namemax + 1);
+}
+
+/* Initialize INF's cache storage.  */
+
+static void
+init_cache (struct inf *inf)
+{
+  int i, offset;
+  struct reg *reg;
+
+  inf->cache = xmalloc (inf->cachesize);
+  for (offset = i = 0; i < inf->nregs; i++)
+    {
+      reg = inf->tnums[i];
+      reg->offset = offset;
+      reg->val.type = val_fetch;
+      reg->val.rawbuf = inf->cache + offset;
+      offset += reg->size;
+    }
+}
+
+/* Initialize INF's pseudo register numbers.  */
+
+static void
+init_pseudo (struct inf *inf, struct regs_init_context *context)
+{
+  struct reg *reg;
+  int i;
+
+  for (i = 0; i < inf->nregs; i++)
+    {
+      reg = inf->regs + i;
+      if (reg->flags & REGS_PSEUDO)
+	reg->tnum = context->max_real_tnum + ++context->npseudos;
+    }
+}
+
+/* Create register child lists in INF.  */
+
+static void
+init_children (struct inf *inf)
+{
+  struct reg *reg, *reg2;
+  int i, j, *pbuf, plen, *parent, nparents, *ccounts;
+
+  /* Allocate space for copying and sorting parent lists.  */
+  plen = 1;
+  pbuf = xmalloc (sizeof (int));
+
+  /* Allocate space for counting each register's children.  */
+  ccounts = xcalloc (inf->nregs, sizeof (int));
+
+  /* Add child lists to registers.  */
+  for (i = 0; i < inf->nregs; i++)
+    {
+      reg = inf->regs + i;
+
+      parent = reg->parents;
+      if (!parent)
+	continue;
+
+      /* Count the parent list.  */
+      while (*parent >= 0)
+	parent++;
+      nparents = parent - reg->parents;
+
+      /* Sort a copy of the parent list.  */
+      if (nparents > plen)
+	{
+	  plen = nparents;
+	  free (pbuf);
+	  pbuf = xmalloc (plen * sizeof (int));
+	}
+      memcpy (pbuf, reg->parents, (nparents + 1) * sizeof (int));
+      qsort (pbuf, nparents, sizeof (int), intcmp);
+
+      /* Add the register to each of its parents' child lists.  */
+      for (parent = pbuf; *parent >= 0; parent++)
+	{
+	  if (parent > pbuf && parent[-1] == *parent)
+	    continue;
+	  reg2 = find (parent, inf->tnums, inf->nregs, find_tnum_cmp);
+	  if (!reg2)
+	    internal_error (_"init_children: no register %d", *parent);
+
+	  j = reg2 - inf->regs;
+	  if (!ccounts[j])
+	    reg2->children = xmalloc (2 * sizeof (struct reg *));
+	  else
+	    reg2->children = xrealloc (reg2->children, (ccounts[j] + 2)
+				       * sizeof (struct reg *));
+	  reg2->children[ccounts[j]++] = reg;
+	}
+    }
+
+  /* Null-terminate dependent lists.  */
+  for (i = 0; i < inf->nregs; i++)
+    {
+      if (!ccounts[i])
+	inf->regs[i].children = NULL;
+      else
+	inf->regs[i].children[ccounts[i]] = NULL;
+    }
+
+  free (pbuf);
+  free (ccounts);
+}
+
+/* Begin initializing GDBARCH fields handled by this module.  Architectures
+   should call this function, individual register definition functions like
+   regs_init_real(), and regs_init_finish() from their gdbarch_register()
+   callbacks.
+
+   Many quantities initialized here, e.g. num_regs, can't be initialized by a
+   register_gdbarch_data() callback because they must be initialized before
+   those callbacks get called.  */
+
+struct regs_init_context *
+regs_init_start (struct gdbarch *gdbarch, regs_caller_ftype caller_regs)
+{
+  struct regs_init_context *context;
+  struct inf *inf;
+
+  context = xmalloc (sizeof *context);
+  context->gdbarch = gdbarch;
+  context->inf = inf = xmalloc (sizeof (struct inf));
+
+  inf->caller_regs = caller_regs;
+  inf->remap = NULL;
+  inf->regs = NULL;
+  inf->nregs = 0;
+  inf->nmregs = 0;
+
+  /* Prepare to accumulate various statistics.  */
+  inf->namemax = inf->cachesize = inf->rawmax = 0;
+  context->virtmax = 0;
+  context->max_real_tnum = -1;
+  context->npseudos = 0;
+  context->regssz = 0;
+
+  return context;
+}
+
+/* Define in CONTEXT a register with attributes specified by the argument
+   list.  This is the back end for all public register definition
+   functions.  */
+
+static void
+init_any (struct regs_init_context *context, char *name, int tnum,
+	  int dnum, int size, struct type **type, CORE_ADDR mem,
+	  unsigned int flags, regs_rpseudo_ftype rpseudo,
+	  regs_wpseudo_ftype wpseudo, void *pseudo_data, int *parents)
+{
+  struct inf *inf; struct reg *reg;
+  int namelen, i;
+
+  inf = context->inf;
+
+  /* Double the array size every time it reaches a power of 2.  */
+  if (context->regssz == 0)
+    {
+      context->regssz = 1;
+      inf->regs = xmalloc (sizeof (struct reg));
+    }
+  else if (context->regssz == inf->nregs)
+    {
+      context->regssz *= 2;
+      inf->regs = xrealloc (inf->regs, context->regssz * sizeof (struct reg));
+    }
+  reg = inf->regs + inf->nregs;
+
+  /* Copy attributes.  */
+  if (!name)
+    reg->name = NULL;
+  else
+    reg->name = strdup (name);
+  reg->tnum = tnum;
+  reg->dnum = dnum;
+  reg->size = size;
+  reg->type = type;
+  reg->mem = mem;
+  reg->flags = flags;
+  reg->rpseudo = rpseudo;
+  reg->wpseudo = wpseudo;
+  reg->pseudo_data = pseudo_data;
+
+  if (!parents)
+    reg->parents = NULL;
+  else
+    {
+      for (i = 0; parents[i] >= 0; i++)
+	;
+      reg->parents = xmalloc ((i + 1) * sizeof (int));
+      memcpy (reg->parents, parents, (i + 1) * sizeof (int));
+    }
+
+  /* Infer some flags.  */
+  if (mem != -1)
+    reg->flags |= REGS_MAPPED;
+
+  if (!name)
+    reg->flags |= REGS_HIDEALL;
+  if (reg->flags & REGS_HIDEALL)
+    reg->flags |= REGS_HIDESOME;
+
+  if (!rpseudo && !wpseudo)
+    reg->flags |= REGS_REAL;
+  else
+    reg->flags |= REGS_PSEUDO;
+
+  /* Accumulate various statistics.  */
+  inf->nregs++;
+  inf->cachesize += size;
+  if (name)
+    inf->nnregs++;
+  if (mem != -1)
+    inf->nmregs++;
+
+  /* Record maximum name length.  */
+  if (name)
+    {
+      namelen = strlen (name);
+      if (namelen > inf->namemax)
+	inf->namemax = namelen;
+    }
+
+  /* Notice maximum register number.  */
+  if (tnum > context->max_real_tnum)
+    context->max_real_tnum = tnum;
+
+  /* Record maximum sizes.  */
+  if (size > inf->rawmax)
+    inf->rawmax = size;
+  size = TYPE_LENGTH (*type);
+  if (size > context->virtmax)
+    context->virtmax = size;
+}
+
+/* Define a real register in CONTEXT.  */
+
+void
+regs_init_real (struct regs_init_context *context, char *name, int tnum,
+		int size, struct type **type, unsigned int flags)
+{
+  init_any (context, name, tnum, tnum, size, type, -1, flags,
+	    NULL, NULL, NULL, NULL);
+}
+
+/* Define a real vector register in CONTEXT.  */
+
+void
+regs_init_vec (struct regs_init_context *context, char *name, int tnum,
+	       int size, struct type **type, unsigned int flags)
+{
+  init_any (context, name, tnum, tnum, size, type, -1, flags,
+	    NULL, NULL, NULL, NULL);
+}
+
+/* Define a real memory-mapped register in CONTEXT.  */
+
+void
+regs_init_mem  (struct regs_init_context *context, char *name, int tnum,
+		int size, struct type **type, CORE_ADDR mem,
+		unsigned int flags)
+{
+  init_any (context, name, tnum, tnum, size, type, mem, flags,
+	    NULL, NULL, NULL, NULL);
+}
+
+/* Define a pseudo register in CONTEXT.  The register's GDB internal number
+   will be autogenerated later.  */
+
+void
+regs_init_pseudo (struct regs_init_context *context, char *name, int size,
+		  struct type **type, CORE_ADDR mem, unsigned int flags,
+		  regs_rpseudo_ftype rpseudo, regs_wpseudo_ftype wpseudo,
+		  void *data, int *parents)
+{
+  init_any (context, name, 0, 0, size, type, mem, flags,
+	    rpseudo, wpseudo, data, parents);
+}
+
+/* Allocate and initialize a copy of REMAP_DATA, and pass the address of that
+   copy to REMAP() whenever the register memory map is checked.
+
+   REMAP() can change the map by calling regs_remap().  It returns 1 if it
+   changed the map and 0 otherwise.  */
+
+void
+regs_init_remap (struct regs_init_context *context, regs_remap_ftype remap,
+		 void *data)
+{
+  struct inf *inf;
+
+  inf = context->inf;
+  inf->remap = remap;
+  inf->remap_data = data;
+}
+
+/* Finish the initialization work started by regs_init_start().  */
+
+void
+regs_init_finish (struct regs_init_context *context)
+{
+  struct gdbarch *gdbarch;
+  struct inf *inf;
+
+  gdbarch = context->gdbarch;
+  inf = context->inf;
+
+  /* Free extra memory allocated for the register array.  */
+  inf->regs = xrealloc (inf->regs, inf->nregs * sizeof (struct reg));
+
+  init_pseudo (inf, context);
+  init_lookups (inf);
+  init_cache (inf);
+  init_children (inf);
+
+  /* Set gdbarch fields.  */
+  set_gdbarch_num_regs (gdbarch, context->max_real_tnum + 1);
+  set_gdbarch_num_pseudo_regs (gdbarch, context->npseudos);
+  set_gdbarch_register_name (gdbarch, regs_register_name);
+  set_gdbarch_register_bytes (gdbarch, inf->cachesize);
+  set_gdbarch_register_byte (gdbarch, regs_register_byte);
+  set_gdbarch_register_raw_size (gdbarch, regs_register_raw_size);
+  set_gdbarch_max_register_raw_size (gdbarch, inf->rawmax);
+  set_gdbarch_register_virtual_size (gdbarch, regs_register_virtual_size);
+  set_gdbarch_register_name_tnum (gdbarch, regs_register_name_tnum);
+  set_gdbarch_register_cached (gdbarch, regs_register_cached);
+  set_gdbarch_set_register_cached (gdbarch, regs_set_register_cached);
+  set_gdbarch_register_buffer (gdbarch, regs_register_buffer);
+  set_gdbarch_real_register (gdbarch, regs_real_register);
+  set_gdbarch_pseudo_register (gdbarch, regs_pseudo_register);
+  set_gdbarch_register_info_first (gdbarch, regs_register_info_first);
+  set_gdbarch_register_info_next (gdbarch, regs_register_info_next);
+  set_gdbarch_register_addr_tnum (gdbarch, regs_register_addr_tnum);
+  set_gdbarch_register_write_memory (gdbarch, regs_register_write_memory);
+  set_gdbarch_register_hidesome (gdbarch, regs_register_hidesome);
+  set_gdbarch_register_hideall (gdbarch, regs_register_hideall);
+  set_gdbarch_register_rdonly (gdbarch, regs_register_rdonly);
+  set_gdbarch_register_reffect (gdbarch, regs_register_reffect);
+  set_gdbarch_fetch_frame_register (gdbarch, regs_fetch_frame);
+  set_gdbarch_max_register_virtual_size (gdbarch, context->virtmax);
+  set_gdbarch_register_virtual_type (gdbarch, regs_register_virtual_type);
+  set_gdbarch_init_extra_frame_info (gdbarch, regs_init_extra_frame_info);
+  set_gdbarch_frame_init_saved_regs (gdbarch, regs_frame_init_saved_regs);
+  set_gdbarch_get_saved_register (gdbarch, regs_get_saved_register);
+  set_gdbarch_pop_frame (gdbarch, regs_pop_frame);
+  set_gdbarch_frame_saved_pc (gdbarch, regs_frame_saved_pc);
+  set_gdbarch_frame_chain (gdbarch, regs_frame_chain);
+  set_gdbarch_fetch_pseudo_register (gdbarch, regs_fetch_pseudo_register);
+  set_gdbarch_store_pseudo_register (gdbarch, regs_store_pseudo_register);
+  set_gdbarch_regcache_module_active (gdbarch, 0);
+  set_gdbarch_data (gdbarch, inf_id, inf);
+
+  /* gdbarch_register_size()'s name makes it seem like a candidate for
+     autogeneration, but in fact it represents (as far as I can tell) the size
+     of an instruction, which isn't inferable from the information in struct
+     gdbreg.
+
+     It might make sense to add a .convertible field to struct gdbreg, for
+     initializing gdbarch_register_convertible().  Probably other fields
+     would be useful and could be added.  */
+
+  free (context);
+}
+
+/* Module initialization.  */
+
+void
+_initialize_regs (void)
+{
+  inf_id = register_gdbarch_data (NULL, NULL);
+}
Index: gdb/regs.h
===================================================================
diff -up /dev/null gdb/regs.h
--- /dev/null	Sun Feb 12 03:29:56 1995
+++ gdb/regs.h	Tue Feb 13 23:09:38 2001
@@ -0,0 +1,268 @@
+/* Target register definition interface for GDB, the GNU debugger.
+   Copyright 2000 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.  */
+
+/* This module implements a multi-arch interface for defining registers.  It
+   allows a multi-arch *-tdep.c file to specify one or more register sets for
+   one or more different architectures.
+
+   Sample usage:
+
+     context = regs_init_start (gdbarch, mips_caller_regs);
+     regs_init_real (context, "r0", 0, 4, &builtin_type_int32, 0);
+     regs_init_real (context, "r1", 1, 4, &builtin_type_int32, 0);
+     regs_init_real (context, "r2", 2, 4, &builtin_type_int32, 0);
+     ...
+     parents[0] = 2;
+     parents[1] = -1;
+     regs_init_pseudo (context, "r2_alias", 4, &builtin_type_int32,
+                       REGS_HIDEALL, regs_rpseudo_alias, regs_wpseudo_alias,
+                       parents);
+     ...
+     regs_init_finish (context);
+
+   Each defined register has the following attributes:
+
+     - name
+     - target number (aka "tnum")
+     - debug info number (aka "dnum")
+     - zero-based index number, determined by the order in which registers
+       are defined
+     - raw size
+     - virtual size
+     - virtual type
+     - offset in the cache buffer, which contains packed values sorted by
+       target number
+     - memory-mapped address
+     - pseudo-register read/write callbacks
+     - pseudo-register parent registers (dependencies)
+     - various flags
+
+   regs_init_real(), regs_init_mem(), and regs_init_pseudo() respectively
+   define real, memory-mapped, and pseudo registers with appropriate default
+   attributes.  Other register definition functions should be added as needed.
+
+   If cliregs_info() is used, "info registers" and "info all-registers"
+   sort registers in increasing order of index number.
+
+   regs_init_finish() installs callbacks for the following multi-arch
+   functions:
+
+     gdbarch_num_regs
+     gdbarch_num_pseudo_regs
+     gdbarch_register_name
+     gdbarch_register_bytes
+     gdbarch_register_byte
+     gdbarch_register_raw_size
+     gdbarch_max_register_raw_size
+     gdbarch_register_virtual_size
+     gdbarch_max_register_virtual_size
+     gdbarch_register_virtual_type
+     gdbarch_get_saved_register
+     gdbarch_pop_frame
+     gdbarch_frame_saved_pc
+     gdbarch_frame_chain
+     gdbarch_fetch_pseudo_register
+     gdbarch_store_pseudo_register
+     gdbarch_do_registers_info
+
+   Targets may install their own versions of any of those functions by calling
+   set_gdbarch_*() after regs_init_finish() returns.
+
+   Register target numbers are used as opaque identifiers when communicating
+   with remote stubs.  Therefore, to avoid breaking stubs, target numbers
+   should never change after they're chosen.
+
+   To define a pseudo-register, an architecture specifies a list of parent
+   registers and callbacks to read and write the pseudo-register.  This module
+   handles invalidating a pseudo-register when changing a parent register on
+   which the pseudo-register depends.
+
+   If a GDB user writes to the inferior's memory at a location where a
+   memory-mapped register is mapped, the user sees the new value when
+   examining the register.
+
+   Possible future enhancement: Targets might receive register blocks from the
+   hardware with padding between certain registers, in which case it might be
+   useful to add a pad field.
+
+   Current restrictions:
+     - register memory mapped locations must not overlap
+     - pseudo-register parents must be real registers */
+
+#ifndef GDB_REGS_H
+# define GDB_REGS_H
+
+/* Register flag bits.  */
+
+enum
+  {
+    REGS_HIDESOME = 0x01,	/* don't display in "info registers" */
+    REGS_HIDEALL = 0x02,	/* don't display in "info registers" or "info
+				   all-registers" */
+    REGS_RDONLY = 0x04,		/* register is read-only */
+    REGS_RTHRU = 0x08,		/* don't cache reads */
+    REGS_WTHRU = 0x10,		/* don't cache writes (not implemented) */
+    REGS_REFFECT = 0x20		/* reads have side-effects, so don't display
+				   during "info [all-]registers" unless
+				   explicitly requested */
+  };
+
+/* Callback for implementing saved register lookups.  It should update FRAME's
+   caller register state from FRAME's to its caller's.  regs_get_caller(),
+   regs_set_caller(), and regs_copy_caller() can be used for querying and
+   changing FRAME's caller register state.
+
+   If USE_GENERIC_DUMMY_FRAMES is true, then the callback will never be passed
+   a dummy frame argument.  Otherwise, the callback is responsible for
+   noticing dummy frames and copying saved dummy caller register state.  */
+
+typedef void (*regs_caller_ftype) (struct frame_info *frame);
+
+/* Optional callback to update the register memory map.  If the map needs
+   updating, the callback should update it using regs_remap() and return 1,
+   else it should return 0.
+
+   DATA points to per-architecture storage allocated by the register module
+   and initialized by regs_init_remap().  */
+
+typedef int (*regs_remap_ftype) (void **data);
+
+/* Pseudo-register read and write callback types.  Read or write
+   pseudo-register REGNUM in FRAME to or from RAWBUF.  PARENTS if non-null is
+   a -1 terminated list of real registers on which the pseudo-register
+   depends.
+
+   RAWBUF is guaranteed to be large enough to hold any register, and both read
+   and write callbacks may overwrite it, e.g. for temporary storage.
+
+   Return 1 on success, 0 on failure if a future attempt might succeed, -1
+   otherwise.  */
+
+typedef int (*regs_rpseudo_ftype) (struct frame_info *frame, int regnum,
+				   int *parents, void *data, char *rawbuf);
+typedef int (*regs_wpseudo_ftype) (struct frame_info *frame, int regnum,
+				   int *parents, void *data, char *rawbuf);
+
+/* Start defining an architecture's registers.  */
+
+extern struct regs_init_context *
+regs_init_start (struct gdbarch *gdbarch,
+		 void (*caller_regs) (struct frame_info *));
+
+/* Define a real register.  */
+
+extern void regs_init_real (struct regs_init_context *context, char *name,
+			    int targnum, int size, struct type **type,
+			    unsigned int flags);
+
+/* Define a real memory-mapped register.  */
+
+extern void regs_init_mem (struct regs_init_context *context, char *name,
+			   int targnum, int size, struct type **type,
+			   CORE_ADDR mem, unsigned int flags);
+
+/* Define a pseudo-register.  */
+
+extern void regs_init_pseudo (struct regs_init_context *context, char *name,
+			      int size, struct type **type, CORE_ADDR mem,
+			      unsigned int flags, regs_rpseudo_ftype rpseudo,
+			      regs_wpseudo_ftype wpseudo, void *data,
+			      int *parents);
+
+/* Specify a register remap callback.  */
+
+extern void regs_init_remap (struct regs_init_context *context,
+			     regs_remap_ftype remap, void *data);
+
+/* Finish defining an architecture's registers.  */
+
+extern void regs_init_finish (struct regs_init_context *context);
+
+/* Try to fetch register TNUM's value from FRAME into RAWBUF.  Return 1 on
+   success, 0 on failure if a future attempt might succeed, -1 otherwise.  */
+
+extern int regs_fetch_frame (struct frame_info *frame, int tnum, char *rawbuf);
+
+/* Try to store RAWBUF as register TNUM's value in FRAME.  Return
+   success.  */
+
+extern int regs_store_frame (struct frame_info *frame, int tnum, char *rawbuf);
+
+/* Return the value of register TNUM in FRAME.  */
+
+extern ULONGEST regs_get_frame (struct frame_info *frame, int tnum);
+
+/* Return the value of register TNUM in FRAME's caller.  */
+
+extern ULONGEST regs_get_caller (struct frame_info *frame, int tnum);
+
+/* Record the fact that register TNUM's value in FRAME's caller is:
+     - VALUE if LVAL is not_lval
+     - in memory location VALUE if LVAL is lval_memory
+     - in register TNUM if LVAL is lval_register  */
+
+extern void regs_set_caller (struct frame_info *frame, int tnum,
+			     enum lval_type lval, ULONGEST value);
+
+/* Copy register TNUM1's caller information in FRAME to register
+   TNUM2's.  */
+
+extern void regs_copy_caller (struct frame_info *frame, int tnum1, int tnum2);
+
+/* Set each memory-mapped register's memory location to ADJUST (<regnum>,
+   <mem>, DATA) where <regnum> and <mem> are the register's target number and
+   current memory location, respectively.  */
+
+extern void regs_remap (CORE_ADDR (*adjust) (int, CORE_ADDR, void *),
+			void *data);
+
+/* Pseudo-register callbacks to implement register aliases.  */
+
+extern int regs_rpseudo_alias (struct frame_info *frame, int tnum,
+			       int *parents, void *data, char *rawbuf);
+extern int regs_wpseudo_alias (struct frame_info *frame, int tnum,
+			       int *parents, void *data, char *rawbuf);
+
+/* Pseudo-register callbacks to implement memory registers.  */
+
+extern int regs_rpseudo_mem (struct frame_info *frame, int tnum,
+			     int *parents, void *data, char *rawbuf);
+extern int regs_wpseudo_mem (struct frame_info *frame, int tnum,
+			     int *parents, void *data, char *rawbuf);
+
+/* Pseudo-register callbacks to implement vector registers.  */
+
+extern int regs_rpseudo_vec (struct frame_info *frame, int tnum,
+			     int *parents, void *data, char *rawbuf);
+extern int regs_wpseudo_vec (struct frame_info *frame, int tnum,
+			     int *parents, void *data, char *rawbuf);
+
+/* Pseudo-register read callback to add all parent registers.  */
+
+extern int regs_rpseudo_sum (struct frame_info *frame, int tnum,
+			     int *parents, void *data, char *rawbuf);
+
+/* Pseudo-register write callback to subtract the second parent register
+   from the first.  */
+
+extern int regs_wpseudo_sub (struct frame_info *frame, int tnum,
+			     int *parents, void *data, char *rawbuf);
+
+#endif    /* !GDB_REGS_H */
Index: gdb/remote.c
===================================================================
diff -up gdb/remote.c gdb/remote.c
--- gdb/remote.c	Thu Feb 15 00:53:07 2001
+++ gdb/remote.c	Tue Feb 13 23:09:38 2001
@@ -3092,7 +3092,7 @@ supply_them:
     {
       supply_register (i, &regs[REGISTER_BYTE (i)]);
       if (buf[REGISTER_BYTE (i) * 2] == 'x')
-	set_register_cached (i, -1);
+	SET_REGISTER_CACHED (i, -1);
     }
 }
 
@@ -3129,7 +3129,7 @@ store_register_using_P (int regno)
 
   sprintf (buf, "P%x=", regno);
   p = buf + strlen (buf);
-  regp = register_buffer (regno);
+  regp = REGISTER_BUFFER (regno);
   for (i = 0; i < REGISTER_RAW_SIZE (regno); ++i)
     {
       *p++ = tohex ((regp[i] >> 4) & 0xf);
@@ -3189,7 +3189,7 @@ remote_store_registers (int regno)
   /* Command describes registers byte by byte,
      each byte encoded as two hex characters.  */
 
-  regs = register_buffer (-1);
+  regs = REGISTER_BUFFER (-1);
   p = buf + 1;
   /* remote_prepare_to_store insures that register_bytes_found gets set.  */
   for (i = 0; i < register_bytes_found; i++)
Index: gdb/target.c
===================================================================
diff -up gdb/target.c gdb/target.c
--- gdb/target.c	Thu Feb 15 00:53:19 2001
+++ gdb/target.c	Tue Feb 13 23:09:38 2001
@@ -856,6 +856,10 @@ do_xfer_memory (CORE_ADDR memaddr, char 
   if (len == 0)
     return 0;
 
+  /* Deal with memory-mapped registers.  */
+  if (write && REGISTER_WRITE_MEMORY_P ())
+    REGISTER_WRITE_MEMORY (memaddr, len);
+
   /* to_xfer_memory is not guaranteed to set errno, even when it returns
      0.  */
   errno = 0;
Index: gdb/value.h
===================================================================
diff -up gdb/value.h gdb/value.h
--- gdb/value.h	Thu Feb 15 00:53:26 2001
+++ gdb/value.h	Tue Feb 13 23:09:38 2001
@@ -499,10 +499,36 @@ extern void register_changed (int regnum
 
 extern char *register_buffer (int regnum);
 
+extern int real_register (int regnum);
+
+extern int pseudo_register (int regnum);
+
+extern int register_info_first (void);
+
+extern int register_info_next (int regnum);
+
+extern int register_hidesome (int regnum);
+
+extern int register_hideall (int regnum);
+
+extern int register_rdonly (int regnum);
+
+extern int register_reffect (int regnum);
+
+extern int register_memonly (int regnum);
+
+extern int fetch_frame_register (struct frame_info *frame, int regnum,
+				 char *rawbuf);
+
 extern void get_saved_register (char *raw_buffer, int *optimized,
 				CORE_ADDR * addrp,
 				struct frame_info *frame,
 				int regnum, enum lval_type *lval);
+
+extern int read_relative_register_raw_bytes (int regnum, char *myaddr);
+
+extern int read_relative_register_raw_bytes_for_frame
+  (int regnum, char *myaddr, struct frame_info *frame);
 
 extern void
 modify_field (char *addr, LONGEST fieldval, int bitpos, int bitsize);


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: A better register interface
  2001-02-14 22:20 ` A better register interface Nick Duffek
@ 2001-02-15  7:38   ` Fernando Nasser
  2001-02-15  8:40   ` Andrew Cagney
  1 sibling, 0 replies; 3+ messages in thread
From: Fernando Nasser @ 2001-02-15  7:38 UTC (permalink / raw)
  To: Nick Duffek; +Cc: gdb-patches

Just to let all know that Insight will benefit a lot from this new
interface.  We badly need it to be able to provide a better Register
Window.

We also have an enhanced support for Pentium III processors (mostly for
embedded as the native depends on the OS) with lots of additional
registers that we would like to make available in the FSF GDB sources. 
THis new register interface would also make this much easier.

-- 
Fernando Nasser
Red Hat Canada Ltd.                     E-Mail:  fnasser@redhat.com
2323 Yonge Street, Suite #300
Toronto, Ontario   M4P 2C9


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: A better register interface
  2001-02-14 22:20 ` A better register interface Nick Duffek
  2001-02-15  7:38   ` Fernando Nasser
@ 2001-02-15  8:40   ` Andrew Cagney
  1 sibling, 0 replies; 3+ messages in thread
From: Andrew Cagney @ 2001-02-15  8:40 UTC (permalink / raw)
  To: Nick Duffek; +Cc: gdb-patches

Nick,

Can you please break your jumbo patch down into three parts:

	o	the cli code

	o	the architecture vector changes
		- especially in the context of
		my e-mail ``a better register interface''

		Your code may may address the bugs.  I don't
		know that it is addressing the underlying problem.

	o	your alternative regs.c implementation.

Andrew


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2001-02-15  8:40 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <3A8B5C60.92EEABA3@cygnus.com>
2001-02-14 22:20 ` A better register interface Nick Duffek
2001-02-15  7:38   ` Fernando Nasser
2001-02-15  8:40   ` Andrew Cagney

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox