This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
Re: [RFA] New register definition interface
- To: Nicholas Duffek <nsd at redhat dot com>
- Subject: Re: [RFA] New register definition interface
- From: Fernando Nasser <fnasser at cygnus dot com>
- Date: Wed, 03 Jan 2001 16:47:18 -0500
- CC: gdb-patches at sources dot redhat dot com
- Organization: Red Hat , Inc. - Toronto
- References: <200101032042.PAA14850@nog.bosbc.com>
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 ®isters[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 ®->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, ®->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, ®->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