This is the mail archive of the gdb@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: A better register interface


On 14-Feb-2001, Andrew Cagney wrote:

>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);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]