This is the mail archive of the gdb-patches@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: [RFA] New register definition interface


To help expedite this thing (as I want to try and use it) I stopped what
I was doing to approve the patches related to the CLI.

The cli-regs.c is approved as is.

I found something strange on the header file though: The guard should be 
CLI_REGS_H, not CLI_DECODE_H.  I guess this was one of those cut-and-paste
things I do so often.

And we usually add a /* CLI_REGS_H */ on the endif statement.
Have I forget it on the cli-decode.h file?

It is approved after this is fixed.

Thanks again.

Fernando


> 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  Wed Jan  3 15:08:48 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_DECODE_H)
> +# define CLI_DECODE_H 1
> +
> +/* DO_REGISTERS_INFO callback.  */
> +
> +extern void cliregs_info (int tnum, int all);
> +
> +#endif
> Index: gdb/gdbarch.c
> ===================================================================
> diff -up gdb/gdbarch.c gdb/gdbarch.c
> --- gdb/gdbarch.c       Wed Jan  3 15:37:28 2001
> +++ gdb/gdbarch.c       Wed Jan  3 15:36:22 2001
> @@ -168,6 +168,7 @@ struct gdbarch
>    int max_register_virtual_size;
>    gdbarch_register_virtual_type_ftype *register_virtual_type;
>    gdbarch_do_registers_info_ftype *do_registers_info;
> +  void * register_list;
>    gdbarch_register_sim_regno_ftype *register_sim_regno;
>    gdbarch_register_bytes_ok_ftype *register_bytes_ok;
>    int use_generic_dummy_frames;
> @@ -316,6 +317,7 @@ struct gdbarch startup_gdbarch =
>    0,
>    0,
>    0,
> +  0,
>    generic_get_saved_register,
>    0,
>    0,
> @@ -940,6 +942,11 @@ gdbarch_dump (struct gdbarch *gdbarch, s
>                        "DO_REGISTERS_INFO(reg_nr, fpregs)",
>                        XSTRING (DO_REGISTERS_INFO (reg_nr, fpregs)));
>  #endif
> +#ifdef REGISTER_LIST
> +  fprintf_unfiltered (file,
> +                      "gdbarch_dump: REGISTER_LIST # %s\n",
> +                      XSTRING (REGISTER_LIST));
> +#endif
>  #ifdef REGISTER_SIM_REGNO
>    fprintf_unfiltered (file,
>                        "gdbarch_dump: %s # %s\n",
> @@ -1607,6 +1614,11 @@ gdbarch_dump (struct gdbarch *gdbarch, s
>                          (long) current_gdbarch->do_registers_info
>                          /*DO_REGISTERS_INFO ()*/);
>  #endif
> +#ifdef REGISTER_LIST
> +  fprintf_unfiltered (file,
> +                      "gdbarch_dump: REGISTER_LIST = %ld\n",
> +                      (long) REGISTER_LIST);
> +#endif
>  #ifdef REGISTER_SIM_REGNO
>    if (GDB_MULTI_ARCH)
>      fprintf_unfiltered (file,
> @@ -2760,6 +2772,21 @@ set_gdbarch_do_registers_info (struct gd
>                                 gdbarch_do_registers_info_ftype do_registers_info)
>  {
>    gdbarch->do_registers_info = do_registers_info;
> +}
> +
> +void *
> +gdbarch_register_list (struct gdbarch *gdbarch)
> +{
> +  if (gdbarch_debug >= 2)
> +    fprintf_unfiltered (gdb_stdlog, "gdbarch_register_list called\n");
> +  return gdbarch->register_list;
> +}
> +
> +void
> +set_gdbarch_register_list (struct gdbarch *gdbarch,
> +                           void * register_list)
> +{
> +  gdbarch->register_list = register_list;
>  }
> 
>  int
> Index: gdb/gdbarch.h
> ===================================================================
> diff -up gdb/gdbarch.h gdb/gdbarch.h
> --- gdb/gdbarch.h       Wed Jan  3 15:37:37 2001
> +++ gdb/gdbarch.h       Wed Jan  3 15:36:05 2001
> @@ -604,6 +604,17 @@ extern void set_gdbarch_do_registers_inf
>  #endif
>  #endif
> 
> +/* If non-null, register definition list provided by the target.  See regs.h
> +   for details. */
> +
> +extern void * gdbarch_register_list (struct gdbarch *gdbarch);
> +extern void set_gdbarch_register_list (struct gdbarch *gdbarch, void * register_list);
> +#if GDB_MULTI_ARCH
> +#if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) || !defined (REGISTER_LIST)
> +#define REGISTER_LIST (gdbarch_register_list (current_gdbarch))
> +#endif
> +#endif
> +
>  /* MAP a GDB RAW register number onto a simulator register number.  See
>     also include/...-sim.h. */
> 
> Index: gdb/gdbarch.sh
> ===================================================================
> diff -up gdb/gdbarch.sh gdb/gdbarch.sh
> --- gdb/gdbarch.sh      Wed Jan  3 15:37:53 2001
> +++ gdb/gdbarch.sh      Wed Jan  3 15:35:37 2001
> @@ -392,6 +392,9 @@ 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
> +# If non-null, register definition list provided by the target.  See regs.h
> +# for details.
> +v:2:REGISTER_LIST:void *:register_list
>  # 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 Wed Jan  3 15:38:02 2001
> +++ gdb/parse.c Tue Jan  2 22:49:48 2001
> @@ -46,6 +46,7 @@
>  #include "symfile.h"           /* for overlay functions */
>  #include "inferior.h"          /* for NUM_PSEUDO_REGS.  NOTE: replace
>                                    with "gdbarch.h" when appropriate.  */
> +#include "regs.h"
> 
> 
>  /* Symbols which architectures can redefine.  */
> @@ -115,6 +116,9 @@ int
>  target_map_name_to_register (char *str, int len)
>  {
>    int i;
> +
> +  if (REGISTER_LIST)
> +    return regs_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
> Index: gdb/regcache.c
> ===================================================================
> diff -up gdb/regcache.c gdb/regcache.c
> --- gdb/regcache.c      Wed Jan  3 15:38:10 2001
> +++ gdb/regcache.c      Tue Jan  2 22:49:48 2001
> @@ -25,6 +25,7 @@
>  #include "target.h"
>  #include "gdbarch.h"
>  #include "gdbcmd.h"
> +#include "regs.h"
> 
>  /*
>   * DATA STRUCTURE
> @@ -66,16 +67,26 @@ static int registers_pid = -1;
>  int
>  register_cached (int regnum)
>  {
> -  return register_valid[regnum];
> +  if (REGISTER_LIST)
> +    return regs_valid (regnum);
> +  else
> +    return register_valid[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.
> +
> +   regs.c's caching mechanism requires that this function 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)
>  {
> -  register_valid[regnum] = state;
> +  if (REGISTER_LIST)
> +    regs_set_valid (regnum, state);
> +  else
> +    register_valid[regnum] = state;
>  }
> 
>  /* REGISTER_CHANGED
> @@ -93,7 +104,9 @@ register_changed (int regnum)
>  char *
>  register_buffer (int regnum)
>  {
> -  if (regnum < 0)
> +  if (REGISTER_LIST)
> +    return regs_buffer (regnum);
> +  else if (regnum < 0)
>      return registers;
>    else
>      return &registers[REGISTER_BYTE (regnum)];
> @@ -104,7 +117,10 @@ register_buffer (int regnum)
>  static int
>  real_register (int regnum)
>  {
> -  return regnum >= 0 && regnum < NUM_REGS;
> +  if (REGISTER_LIST)
> +    return regs_real (regnum);
> +  else
> +    return regnum >= 0 && regnum < NUM_REGS;
>  }
> 
>  /* Return whether register REGNUM is a pseudo register.  */
> @@ -112,7 +128,10 @@ real_register (int regnum)
>  static int
>  pseudo_register (int regnum)
>  {
> -  return regnum >= NUM_REGS && regnum < NUM_REGS + NUM_PSEUDO_REGS;
> +  if (REGISTER_LIST)
> +    return regs_pseudo (regnum);
> +  else
> +    return regnum >= NUM_REGS && regnum < NUM_REGS + NUM_PSEUDO_REGS;
>  }
> 
>  /* Fetch register REGNUM into the cache.  */
> @@ -928,10 +947,13 @@ 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 (!REGISTER_LIST)
> +    {
> +      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  Wed Jan  3 15:06:48 2001
> @@ -0,0 +1,1662 @@
> +/* 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.  */
> +
> +#include <stdlib.h>
> +
> +#include "defs.h"
> +#include "inferior.h"
> +#include "arch-utils.h"
> +#include "gdbcore.h"
> +#include "symfile.h"
> +#include "regs.h"
> +#include "cli/cli-regs.h"
> +
> +/* 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 *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 */
> +    void (*caller_regs)                /* callback for locating caller's regs */
> +      (struct frame_info *);
> +  };
> +
> +/* Initialization context returned by regs_init_start().  */
> +
> +struct regs_init_context
> +  {
> +    struct gdbarch *gdbarch;
> +    struct inf *inf;
> +    int virtmax;
> +    int maxtnum;
> +    int regssz;
> +  };
> +
> +/* Memory region search key used by find_mem().  */
> +
> +struct memfind
> +  {
> +    CORE_ADDR addr;            /* start of memory region */
> +    int len;                   /* length of region */
> +  };
> +
> +/* 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;
> +}
> +
> +/* If a register has index number INUM, return that register.  Otherwise, if
> +   !CALLER, return null, else throw an error message identifying CALLER.  */
> +
> +static struct reg *
> +find_inum (int inum, char *caller)
> +{
> +  struct inf *inf;
> +  struct reg *reg;
> +
> +  inf = REGISTER_LIST;
> +  if (inum >= 0 && inum < inf->nregs)
> +    return inf->regs + inum;
> +  if (caller)
> +    internal_error ("%s: invalid register index number %d", caller, inum);
> +  return NULL;
> +}
> +
> +/* 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 = REGISTER_LIST;
> +  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 = REGISTER_LIST;
> +  if (!inf->nmregs)
> +    return NULL;
> +
> +  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->data, rawbuf);
> +
> +  val->type = int_valtype (valid, val_pseudo);
> +  memcpy (val->rawbuf, rawbuf, reg->size);
> +}
> +
> +/* Try to store 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->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 = REGISTER_LIST;
> +      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 FRMAE'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 = REGISTER_LIST;
> +  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
> +    target_store_registers (reg->tnum);
> +
> +  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 = REGISTER_LIST;
> +  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;
> +    }
> +}
> +
> +/* 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 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 = REGISTER_LIST;
> +
> +  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 = REGISTER_LIST;
> +  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:
> +      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 = REGISTER_LIST;
> +      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 = REGISTER_LIST;
> +  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 = REGISTER_LIST;
> +  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 register INUM.  */
> +
> +int
> +regs_inum_tnum (int inum)
> +{
> +  struct inf *inf;
> +  struct reg *reg;
> +
> +  inf = REGISTER_LIST;
> +  reg = find_inum (inum, "regs_tnum");
> +  return reg->tnum;
> +}
> +
> +/* Return the name of register INUM.  */
> +
> +char *
> +regs_inum_name (int inum)
> +{
> +  struct inf *inf;
> +  struct reg *reg;
> +
> +  inf = REGISTER_LIST;
> +  reg = find_inum (inum, "regs_name");
> +  return reg->name;
> +}
> +
> +/* Return the type of register INUM.  */
> +
> +struct type *
> +regs_inum_type (int inum)
> +{
> +  struct inf *inf;
> +  struct reg *reg;
> +
> +  inf = REGISTER_LIST;
> +  reg = find_inum (inum, "regs_type");
> +  return *reg->type;
> +}
> +
> +/* Return the size of register INUM.  */
> +
> +int
> +regs_inum_size (int inum)
> +{
> +  struct inf *inf;
> +  struct reg *reg;
> +
> +  inf = REGISTER_LIST;
> +  reg = find_inum (inum, "regs_size");
> +  return reg->size;
> +}
> +
> +/* Return the flags of register INUM.  */
> +
> +unsigned int
> +regs_inum_flags (int inum)
> +{
> +  struct inf *inf;
> +  struct reg *reg;
> +
> +  inf = REGISTER_LIST;
> +  reg = find_inum (inum, "regs_flags");
> +  return reg->flags;
> +}
> +
> +/* 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.  */
> +
> +void
> +regs_memwrite (CORE_ADDR addr, int len)
> +{
> +  struct reg *reg, **found;
> +  struct memfind mem;
> +  struct inf *inf;
> +
> +  inf = REGISTER_LIST;
> +  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.  */
> +
> +  while (found > inf->mems)
> +    {
> +      reg = found[-1];
> +      if (reg->mem + reg->size <= addr)
> +       break;
> +      found--;
> +    }
> +
> +  while (found < inf->mems + inf->nmregs)
> +    {
> +      reg = *found;
> +      if (reg->mem >= addr + len)
> +       break;
> +      set_valid (reg, 0);
> +    }
> +}
> +
> +/* Return the target number of the register with LEN-byte NAME, or -1 if no
> +   such register exists.  */
> +
> +int
> +regs_name_tnum (char *name, int len)
> +{
> +  struct inf *inf;
> +  struct reg *reg;
> +
> +  inf = REGISTER_LIST;
> +  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 the target number of the register mapped to memory ADDR, or -1 if no
> +   such register exists.  */
> +
> +int
> +regs_addr_tnum (CORE_ADDR addr)
> +{
> +  struct reg *reg, **found;
> +  struct memfind mem;
> +  struct inf *inf;
> +
> +  found = find_mem (addr, 1);
> +  if (!found)
> +    return -1;
> +
> +  reg = *found;
> +  if (reg->mem != addr)
> +    return -1;
> +
> +  return reg->tnum;
> +}
> +
> +/* Return the internal number of register TNUM.  */
> +
> +int
> +regs_index (int tnum)
> +{
> +  struct inf *inf;
> +  struct reg *reg;
> +
> +  inf = REGISTER_LIST;
> +  reg = find_tnum (tnum, "regs_index");
> +  return reg - inf->regs;
> +}
> +
> +/* 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.  */
> +
> +int
> +regs_valid (int tnum)
> +{
> +  struct reg *reg;
> +
> +  reg = find_tnum (tnum, "regs_valid");
> +  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.  */
> +
> +void
> +regs_set_valid (int tnum, int state)
> +{
> +  struct reg *reg;
> +
> +  reg = find_tnum (tnum, "regs_set_valid");
> +
> +  /* Ignore pseudo registers, because remote.c incorrectly calls
> +     supply_register() on all registers instead of just the ones fetched.  */
> +  if (reg->flags & REGS_REAL)
> +    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.  */
> +
> +char *
> +regs_buffer (int tnum)
> +{
> +  struct reg *reg;
> +  struct inf *inf;
> +
> +  inf = REGISTER_LIST;
> +  if (tnum < 0)
> +    return inf->cache;
> +  else
> +    {
> +      reg = find_tnum (tnum, "regs_buffer");
> +      return reg->val.rawbuf;
> +    }
> +}
> +
> +/* Return the number of registers in the current architecture.  */
> +
> +int
> +regs_count (void)
> +{
> +  struct inf *inf;
> +
> +  inf = REGISTER_LIST;
> +  return inf->nregs;
> +}
> +
> +/* Return whether register TNUM is a real (not generated and not pseudo)
> +   register.  */
> +
> +int
> +regs_real (int tnum)
> +{
> +  struct reg *reg;
> +
> +  reg = find_tnum (tnum, NULL);
> +  return reg && reg->flags & REGS_REAL;
> +}
> +
> +/* Return whether register TNUM is a pseudo register.  */
> +
> +int
> +regs_pseudo (int tnum)
> +{
> +  struct reg *reg;
> +
> +  reg = find_tnum (tnum, NULL);
> +  return reg && reg->flags & REGS_PSEUDO;
> +}
> +
> +/* 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;
> +}
> +
> +/* Initialize INF's register lookup mechanisms.  */
> +
> +static void
> +init_lookups (struct inf *inf)
> +{
> +  struct reg *reg;
> +  int i, j, k;
> +
> +  inf->tnums = (struct reg **) xmalloc (sizeof (struct reg *) * inf->nregs);
> +
> +  if (inf->nnregs)
> +    inf->names = (struct reg **) xmalloc (sizeof (struct reg *) * inf->nnregs);
> +  else
> +    inf->names = NULL;
> +
> +  if (inf->nmregs)
> +    inf->mems = (struct reg **) 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 = (char *) xmalloc (inf->namemax + 1);
> +}
> +
> +/* Initialize INF's cache storage.  */
> +
> +static void
> +init_cache (struct inf *inf)
> +{
> +  int i, offset;
> +  struct reg *reg;
> +
> +  inf->cache = (char *) 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->maxtnum;
> +    }
> +}
> +
> +/* 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 = (int *) xmalloc (sizeof (int));
> +
> +  /* Allocate space for counting each register's children.  */
> +  ccounts = (int *) 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 = (int *) 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 =
> +             (struct reg **) xmalloc (2 * sizeof (struct reg *));
> +         else
> +           reg2->children =
> +             (struct reg **) 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.  Target modules
> +   should call this, individual register definition functions like
> +   regs_init_real(), and regs_init_finish() from their gdbarch_register()
> +   callback.
> +
> +   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.
> +
> +   CALLER_REGS (<frame>) is a 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 CALLER_REGS will never be passed
> +   a dummy frame argument.  Otherwise, CALLER_REGS is responsible for noticing
> +   dummy frames and copying saved dummy caller register state.  */
> +
> +struct regs_init_context *
> +regs_init_start (struct gdbarch *gdbarch,
> +                void (*caller_regs) (struct frame_info *))
> +{
> +  struct regs_init_context *context;
> +  struct inf *inf;
> +
> +  context = (struct regs_init_context *) xmalloc (sizeof *context);
> +  context->gdbarch = gdbarch;
> +  context->inf = inf = (struct inf *) xmalloc (sizeof (struct inf));
> +
> +  inf->caller_regs = caller_regs;
> +  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->maxtnum = -1;
> +  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 *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 = (struct reg *) xmalloc (sizeof (struct reg));
> +    }
> +  else if (context->regssz == inf->nregs)
> +    {
> +      context->regssz *= 2;
> +      inf->regs = (struct reg *) 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->data = data;
> +
> +  if (!parents)
> +    reg->parents = NULL;
> +  else
> +    {
> +      for (i = 0; parents[i] >= 0; i++)
> +       ;
> +      reg->parents = (int *) 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->maxtnum)
> +    context->maxtnum = 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, unsigned int flags,
> +                 regs_rpseudo_ftype rpseudo, regs_wpseudo_ftype wpseudo,
> +                 void *data, int *parents)
> +{
> +  init_any (context, name, 0, 0, size, type, -1, flags,
> +           rpseudo, wpseudo, data, parents);
> +}
> +
> +/* 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 = (struct reg *) xrealloc (inf->regs, inf->nregs
> +                                      * sizeof (struct reg));
> +
> +  init_lookups (inf);
> +  init_cache (inf);
> +  init_pseudo (inf, context);
> +  init_children (inf);
> +
> +  /* Set gdbarch fields.  */
> +  set_gdbarch_register_list (gdbarch, inf);
> +  set_gdbarch_num_regs (gdbarch, context->maxtnum + 1);
> +  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_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_do_registers_info (gdbarch, cliregs_info);
> +
> +  /* 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);
> +}
> Index: gdb/regs.h
> ===================================================================
> diff -up /dev/null gdb/regs.h
> --- /dev/null   Sun Feb 12 03:29:56 1995
> +++ gdb/regs.h  Tue Jan  2 22:49:48 2001
> @@ -0,0 +1,290 @@
> +/* 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
> +
> +/* Pseudo-register read and write callback types.  Read or write
> +   pseudo-register REGNUM in FRAME to or from RAWBUF, reading or writing data
> +   in the real registers in -1-terminated list PARENTS.
> +
> +   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);
> +
> +/* 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_RTHRU = 0x04,         /* don't cache reads */
> +    REGS_WTHRU = 0x08,         /* don't cache writes (not implemented) */
> +    REGS_REFFECT = 0x10,       /* reads have side-effects, so don't display
> +                                  during "info [all-]registers" unless
> +                                  explicitly requested */
> +    REGS_MEMONLY = 0x20                /* access register through memory
> +                                  (memory-mapped registers only) */
> +  };
> +
> +/* 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 memaddr, unsigned int flags);
> +
> +/* Define a pseudo-register.  */
> +
> +extern void regs_init_pseudo (struct regs_init_context *context, char *name,
> +                             int size, struct type **type,
> +                             unsigned int flags, regs_rpseudo_ftype rpseudo,
> +                             regs_wpseudo_ftype wpseudo, void *data,
> +                             int *parents);
> +
> +/* 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);
> +
> +/* Translate internal numbers to various other register attributes.  */
> +
> +extern int regs_inum_tnum (int inum);
> +extern char *regs_inum_name (int inum);
> +extern struct type *regs_inum_type (int inum);
> +extern int regs_inum_size (int inum);
> +extern unsigned int regs_inum_flags (int inum);
> +
> +/* 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.  */
> +
> +extern void regs_memwrite (CORE_ADDR addr, int len);
> +
> +/* Return the target number of the register with LEN-byte NAME, or -1 if no
> +   such register exists.  */
> +
> +extern int regs_name_tnum (char *name, int len);
> +
> +/* Return the target number of the register mapped to memory ADDR, or -1 if no
> +   such register exists.  */
> +
> +extern int regs_addr_tnum (CORE_ADDR addr);
> +
> +/* Return the internal number of register TNUM.  */
> +
> +extern int regs_index (int tnum);
> +
> +/* 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.  */
> +
> +extern int regs_valid (int tnum);
> +
> +/* 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.  */
> +
> +extern void regs_set_valid (int tnum, int 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.  */
> +
> +extern char *regs_buffer (int tnum);
> +
> +/* Return the number of registers in the current architecture.  */
> +
> +extern int regs_count (void);
> +
> +/* 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 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);
> +
> +/* Interface between regcache.c and regs.c.  */
> +
> +extern int regs_real (int);
> +extern int regs_pseudo (int);
> +
> +/* gdbarch backward compatibility for non-multiarched targets.  */
> +
> +#ifndef REGISTER_LIST
> +# define REGISTER_LIST 0
> +#endif
> +
> +#endif    /* !GDB_REGS_H */
> Index: gdb/target.c
> ===================================================================
> diff -up gdb/target.c gdb/target.c
> --- gdb/target.c        Wed Jan  3 15:38:40 2001
> +++ gdb/target.c        Tue Jan  2 23:48:43 2001
> @@ -30,6 +30,7 @@
>  #include "bfd.h"
>  #include "symfile.h"
>  #include "objfiles.h"
> +#include "regs.h"
>  #include "gdb_wait.h"
>  #include "dcache.h"
>  #include <signal.h>
> @@ -853,6 +854,10 @@ do_xfer_memory (CORE_ADDR memaddr, char
>    /* Zero length requests are ok and require no work.  */
>    if (len == 0)
>      return 0;
> +
> +  /* Deal with memory-mapped registers.  */
> +  if (write)
> +    regs_memwrite (memaddr, len);
> 
>    /* to_xfer_memory is not guaranteed to set errno, even when it returns
>       0.  */

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

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