* stack.c (frame_info): Use frame_register_unwind instead of

saved_regs.  Mention when the SP is on the stack or in a register.
* frame.h (frame_register_unwind_ftype): Define.  Document.
(struct frame_info): Add field register_unwind and
register_unwind_cache.
(frame_register_unwind): Declare.
(generic_unwind_get_saved_register): Declare.
* frame.c (frame_register_unwind): New function.
(generic_unwind_get_saved_register): New function.
* blockframe.c (generic_call_dummy_register_unwind): New function.
(frame_saved_regs_register_unwind): New function.
(set_unwind_by_pc): New function.
(create_new_frame): New function.
(get_prev_frame): New function.
This commit is contained in:
Andrew Cagney 2002-06-01 20:44:21 +00:00
parent 3352e23e7a
commit 4f4608125d
5 changed files with 414 additions and 31 deletions

View File

@ -1,3 +1,23 @@
2002-06-01 Andrew Cagney <ac131313@redhat.com>
* stack.c (frame_info): Use frame_register_unwind instead of
saved_regs. Mention when the SP is on the stack or in a register.
* frame.h (frame_register_unwind_ftype): Define. Document.
(struct frame_info): Add field register_unwind and
register_unwind_cache.
(frame_register_unwind): Declare.
(generic_unwind_get_saved_register): Declare.
* frame.c (frame_register_unwind): New function.
(generic_unwind_get_saved_register): New function.
* blockframe.c (generic_call_dummy_register_unwind): New function.
(frame_saved_regs_register_unwind): New function.
(set_unwind_by_pc): New function.
(create_new_frame): New function.
(get_prev_frame): New function.
2002-05-30 Andrew Cagney <ac131313@redhat.com>
* a29k-share/: Delete directory.

View File

@ -34,9 +34,28 @@
#include "inferior.h" /* for read_pc */
#include "annotate.h"
#include "regcache.h"
#include "gdb_assert.h"
/* Prototypes for exported functions. */
static void generic_call_dummy_register_unwind (struct frame_info *frame,
void **cache,
int regnum,
int *optimized,
enum lval_type *lval,
CORE_ADDR *addrp,
int *realnum,
void *raw_buffer);
static void frame_saved_regs_register_unwind (struct frame_info *frame,
void **cache,
int regnum,
int *optimized,
enum lval_type *lval,
CORE_ADDR *addrp,
int *realnum,
void *buffer);
void _initialize_blockframe (void);
/* A default FRAME_CHAIN_VALID, in the form that is suitable for most
@ -208,6 +227,27 @@ set_current_frame (struct frame_info *frame)
current_frame = frame;
}
/* Using the PC, select a mechanism for unwinding a frame returning
the previous frame. The register unwind function should, on
demand, initialize the ->context object. */
static void
set_unwind_by_pc (CORE_ADDR pc, CORE_ADDR fp,
frame_register_unwind_ftype **unwind)
{
if (!USE_GENERIC_DUMMY_FRAMES)
/* Still need to set this to something. The ``info frame'' code
calls this function to find out where the saved registers are.
Hopefully this is robust enough to stop any core dumps and
return vaguely correct values.. */
*unwind = frame_saved_regs_register_unwind;
else if (PC_IN_CALL_DUMMY (pc, fp, fp))
*unwind = generic_call_dummy_register_unwind;
else
*unwind = frame_saved_regs_register_unwind;
}
/* Create an arbitrary (i.e. address specified by user) or innermost frame.
Always returns a non-NULL value. */
@ -232,6 +272,9 @@ create_new_frame (CORE_ADDR addr, CORE_ADDR pc)
if (INIT_EXTRA_FRAME_INFO_P ())
INIT_EXTRA_FRAME_INFO (0, fi);
/* Select/initialize an unwind function. */
set_unwind_by_pc (fi->pc, fi->frame, &fi->register_unwind);
return fi;
}
@ -456,6 +499,12 @@ get_prev_frame (struct frame_info *next_frame)
}
}
/* Initialize the code used to unwind the frame PREV based on the PC
(and probably other architectural information). The PC lets you
check things like the debug info at that point (dwarf2cfi?) and
use that to decide how the frame should be unwound. */
set_unwind_by_pc (prev->pc, prev->frame, &prev->register_unwind);
find_pc_partial_function (prev->pc, &name,
(CORE_ADDR *) NULL, (CORE_ADDR *) NULL);
if (PC_IN_SIGTRAMP (prev->pc, name))
@ -1269,6 +1318,141 @@ generic_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun, int nargs,
return;
}
/* Given a call-dummy dummy-frame, return the registers. Here the
register value is taken from the local copy of the register buffer. */
static void
generic_call_dummy_register_unwind (struct frame_info *frame, void **cache,
int regnum, int *optimized,
enum lval_type *lvalp, CORE_ADDR *addrp,
int *realnum, void *bufferp)
{
gdb_assert (frame != NULL);
gdb_assert (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame));
/* Describe the register's location. Generic dummy frames always
have the register value in an ``expression''. */
*optimized = 0;
*lvalp = not_lval;
*addrp = 0;
*realnum = -1;
/* If needed, find and return the value of the register. */
if (bufferp != NULL)
{
char *registers;
#if 1
/* Get the address of the register buffer that contains all the
saved registers for this dummy frame. Cache that address. */
registers = (*cache);
if (registers == NULL)
{
registers = generic_find_dummy_frame (frame->pc, frame->frame);
(*cache) = registers;
}
#else
/* Get the address of the register buffer that contains the
saved registers and then extract the value from that. */
registers = generic_find_dummy_frame (frame->pc, frame->frame);
#endif
gdb_assert (registers != NULL);
/* Return the actual value. */
memcpy (bufferp, registers + REGISTER_BYTE (regnum),
REGISTER_RAW_SIZE (regnum));
}
}
/* Return the register saved in the simplistic ``saved_regs'' cache.
If the value isn't here AND a value is needed, try the next inner
most frame. */
static void
frame_saved_regs_register_unwind (struct frame_info *frame, void **cache,
int regnum, int *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
int *realnump, void *bufferp)
{
/* There is always a frame at this point. And THIS is the frame
we're interested in. */
gdb_assert (frame != NULL);
gdb_assert (!PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame));
/* Load the saved_regs register cache. */
if (frame->saved_regs == NULL)
FRAME_INIT_SAVED_REGS (frame);
if (frame->saved_regs != NULL
&& frame->saved_regs[regnum] != 0)
{
if (regnum == SP_REGNUM)
{
/* SP register treated specially. */
*optimizedp = 0;
*lvalp = not_lval;
*addrp = 0;
*realnump = -1;
if (bufferp != NULL)
store_address (bufferp, REGISTER_RAW_SIZE (regnum),
frame->saved_regs[regnum]);
}
else
{
/* Any other register is saved in memory, fetch it but cache
a local copy of its value. */
*optimizedp = 0;
*lvalp = lval_memory;
*addrp = frame->saved_regs[regnum];
*realnump = -1;
if (bufferp != NULL)
{
#if 1
/* Save each register value, as it is read in, in a
frame based cache. */
void **regs = (*cache);
if (regs == NULL)
{
int sizeof_cache = ((NUM_REGS + NUM_PSEUDO_REGS)
* sizeof (void *));
regs = frame_obstack_alloc (sizeof_cache);
memset (regs, 0, sizeof_cache);
(*cache) = regs;
}
if (regs[regnum] == NULL)
{
regs[regnum]
= frame_obstack_alloc (REGISTER_RAW_SIZE (regnum));
read_memory (frame->saved_regs[regnum], regs[regnum],
REGISTER_RAW_SIZE (regnum));
}
memcpy (bufferp, regs[regnum], REGISTER_RAW_SIZE (regnum));
#else
/* Read the value in from memory. */
read_memory (frame->saved_regs[regnum], bufferp,
REGISTER_RAW_SIZE (regnum));
#endif
}
}
return;
}
/* No luck, assume this and the next frame have the same register
value. If a value is needed, pass the request on down the chain;
otherwise just return an indication that the value is in the same
register as the next frame. */
if (bufferp == NULL)
{
*optimizedp = 0;
*lvalp = lval_register;
*addrp = 0;
*realnump = regnum;
}
else
{
frame_register_unwind (frame->next, regnum, optimizedp, lvalp, addrp,
realnump, bufferp);
}
}
/* Function: get_saved_register
Find register number REGNUM relative to FRAME and put its (raw,
target format) contents in *RAW_BUFFER.

View File

@ -1,4 +1,4 @@
/* Cache and manage the values of registers for GDB, the GNU debugger.
/* Cache and manage frames for GDB, the GNU debugger.
Copyright 1986, 1987, 1989, 1991, 1994, 1995, 1996, 1998, 2000,
2001, 2002 Free Software Foundation, Inc.
@ -26,6 +26,7 @@
#include "value.h"
#include "inferior.h" /* for inferior_ptid */
#include "regcache.h"
#include "gdb_assert.h"
/* FIND_SAVED_REGISTER ()
@ -127,6 +128,95 @@ default_get_saved_register (char *raw_buffer,
*addrp = addr;
}
void
frame_register_unwind (struct frame_info *frame, int regnum,
int *optimizedp, enum lval_type *lvalp,
CORE_ADDR *addrp, int *realnump, void *bufferp)
{
struct frame_unwind_cache *cache;
/* Require all but BUFFERP to be valid. A NULL BUFFERP indicates
that the value proper does not need to be fetched. */
gdb_assert (optimizedp != NULL);
gdb_assert (lvalp != NULL);
gdb_assert (addrp != NULL);
gdb_assert (realnump != NULL);
/* gdb_assert (bufferp != NULL); */
/* NOTE: cagney/2002-04-14: It would be nice if, instead of a
special case, there was always an inner frame dedicated to the
hardware registers. Unfortunatly, there is too much unwind code
around that looks up/down the frame chain while making the
assumption that each frame level is using the same unwind code. */
if (frame == NULL)
{
/* We're in the inner-most frame, get the value direct from the
register cache. */
*optimizedp = 0;
*lvalp = lval_register;
*addrp = 0;
/* Should this code test ``register_cached (regnum) < 0'' and do
something like set realnum to -1 when the register isn't
available? */
*realnump = regnum;
if (bufferp)
read_register_gen (regnum, bufferp);
return;
}
/* Ask this frame to unwind its register. */
frame->register_unwind (frame, &frame->register_unwind_cache, regnum,
optimizedp, lvalp, addrp, realnump, bufferp);
}
void
generic_unwind_get_saved_register (char *raw_buffer,
int *optimizedp,
CORE_ADDR *addrp,
struct frame_info *frame,
int regnum,
enum lval_type *lvalp)
{
int optimizedx;
CORE_ADDR addrx;
int realnumx;
enum lval_type lvalx;
if (!target_has_registers)
error ("No registers.");
/* Keep things simple, ensure that all the pointers (except valuep)
are non NULL. */
if (optimizedp == NULL)
optimizedp = &optimizedx;
if (lvalp == NULL)
lvalp = &lvalx;
if (addrp == NULL)
addrp = &addrx;
/* Reached the the bottom (youngest, inner most) of the frame chain
(youngest, inner most) frame, go direct to the hardware register
cache (do not pass go, do not try to cache the value, ...). The
unwound value would have been cached in frame->next but that
doesn't exist. This doesn't matter as the hardware register
cache is stopping any unnecessary accesses to the target. */
/* NOTE: cagney/2002-04-14: It would be nice if, instead of a
special case, there was always an inner frame dedicated to the
hardware registers. Unfortunatly, there is too much unwind code
around that looks up/down the frame chain while making the
assumption that each frame level is using the same unwind code. */
if (frame == NULL)
frame_register_unwind (NULL, regnum, optimizedp, lvalp, addrp, &realnumx,
raw_buffer);
else
frame_register_unwind (frame->next, regnum, optimizedp, lvalp, addrp,
&realnumx, raw_buffer);
}
#if !defined (GET_SAVED_REGISTER)
#define GET_SAVED_REGISTER(raw_buffer, optimized, addrp, frame, regnum, lval) \
default_get_saved_register(raw_buffer, optimized, addrp, frame, regnum, lval)

View File

@ -23,6 +23,29 @@
#if !defined (FRAME_H)
#define FRAME_H 1
/* Return the location (and possibly value) of REGNUM for the previous
(older, up) frame. All parameters except VALUEP can be assumed to
be non NULL. When VALUEP is NULL, just the location of the
register should be returned.
UNWIND_CACHE is provided as mechanism for implementing a per-frame
local cache. It's initial value being NULL. Memory for that cache
should be allocated using frame_obstack_alloc().
Register window architectures (eg SPARC) should note that REGNUM
identifies the register for the previous frame. For instance, a
request for the value of "o1" for the previous frame would be found
in the register "i1" in this FRAME. */
typedef void (frame_register_unwind_ftype) (struct frame_info *frame,
void **unwind_cache,
int regnum,
int *optimized,
enum lval_type *lvalp,
CORE_ADDR *addrp,
int *realnump,
void *valuep);
/* Describe the saved registers of a frame. */
#if defined (EXTRA_FRAME_INFO) || defined (FRAME_FIND_SAVED_REGS)
@ -112,6 +135,11 @@ struct frame_info
related unwind data. */
struct unwind_contect *context;
/* See description above. Return the register value for the
previous frame. */
frame_register_unwind_ftype *register_unwind;
void *register_unwind_cache;
/* Pointers to the next (down, inner) and previous (up, outer)
frame_info's in the frame cache. */
struct frame_info *next; /* down, inner */
@ -278,6 +306,22 @@ extern void generic_get_saved_register (char *, int *, CORE_ADDR *,
struct frame_info *, int,
enum lval_type *);
extern void generic_unwind_get_saved_register (char *raw_buffer,
int *optimized,
CORE_ADDR * addrp,
struct frame_info *frame,
int regnum,
enum lval_type *lval);
/* Unwind the stack frame so that the value of REGNUM, in the previous
frame is returned. If VALUEP is NULL, don't fetch/compute the
value. Instead just return the location of the value. */
extern void frame_register_unwind (struct frame_info *frame, int regnum,
int *optimizedp, enum lval_type *lvalp,
CORE_ADDR *addrp, int *realnump,
void *valuep);
extern void generic_save_call_dummy_addr (CORE_ADDR lo, CORE_ADDR hi);
extern void get_saved_register (char *raw_buffer, int *optimized,

View File

@ -929,39 +929,84 @@ frame_info (char *addr_exp, int from_tty)
}
}
FRAME_INIT_SAVED_REGS (fi);
if (fi->saved_regs != NULL)
{
/* The sp is special; what's returned isn't the save address, but
actually the value of the previous frame's sp. */
printf_filtered (" Previous frame's sp is ");
print_address_numeric (fi->saved_regs[SP_REGNUM], 1, gdb_stdout);
printf_filtered ("\n");
count = 0;
numregs = NUM_REGS + NUM_PSEUDO_REGS;
for (i = 0; i < numregs; i++)
if (fi->saved_regs[i] && i != SP_REGNUM)
if (fi->saved_regs == NULL)
FRAME_INIT_SAVED_REGS (fi);
/* Print as much information as possible on the location of all the
registers. */
{
enum lval_type lval;
int optimized;
CORE_ADDR addr;
int realnum;
int count;
int i;
int need_nl = 1;
/* The sp is special; what's displayed isn't the save address, but
the value of the previous frame's sp. This is a legacy thing,
at one stage the frame cached the previous frame's SP instead
of its address, hence it was easiest to just display the cached
value. */
if (SP_REGNUM >= 0)
{
/* Find out the location of the saved stack pointer with out
actually evaluating it. */
frame_register_unwind (fi, SP_REGNUM, &optimized, &lval, &addr,
&realnum, NULL);
if (!optimized && lval == not_lval)
{
if (count == 0)
puts_filtered (" Saved registers:\n ");
else
puts_filtered (",");
wrap_here (" ");
printf_filtered (" %s at ", REGISTER_NAME (i));
print_address_numeric (fi->saved_regs[i], 1, gdb_stdout);
count++;
void *value = alloca (MAX_REGISTER_RAW_SIZE);
CORE_ADDR sp;
frame_register_unwind (fi, SP_REGNUM, &optimized, &lval, &addr,
&realnum, value);
sp = extract_address (value, REGISTER_RAW_SIZE (SP_REGNUM));
printf_filtered (" Previous frame's sp is ");
print_address_numeric (sp, 1, gdb_stdout);
printf_filtered ("\n");
need_nl = 0;
}
if (count)
puts_filtered ("\n");
}
else
{
/* We could get some information about saved registers by
calling get_saved_register on each register. Which info goes
with which frame is necessarily lost, however, and I suspect
that the users don't care whether they get the info. */
else if (!optimized && lval == lval_memory)
{
printf_filtered (" Previous frame's sp at ");
print_address_numeric (addr, 1, gdb_stdout);
printf_filtered ("\n");
need_nl = 0;
}
else if (!optimized && lval == lval_register)
{
printf_filtered (" Previous frame's sp in %s\n",
REGISTER_NAME (realnum));
need_nl = 0;
}
/* else keep quiet. */
}
count = 0;
numregs = NUM_REGS + NUM_PSEUDO_REGS;
for (i = 0; i < numregs; i++)
if (i != SP_REGNUM)
{
/* Find out the location of the saved register without
fetching the corresponding value. */
frame_register_unwind (fi, i, &optimized, &lval, &addr, &realnum,
NULL);
/* For moment, only display registers that were saved on the
stack. */
if (!optimized && lval == lval_memory)
{
if (count == 0)
puts_filtered (" Saved registers:\n ");
else
puts_filtered (",");
wrap_here (" ");
printf_filtered (" %s at ", REGISTER_NAME (i));
print_address_numeric (addr, 1, gdb_stdout);
count++;
}
}
if (count || need_nl)
puts_filtered ("\n");
}
}
}
#if 0