mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-28 04:25:10 +08:00
* 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:
parent
3352e23e7a
commit
4f4608125d
@ -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.
|
||||
|
184
gdb/blockframe.c
184
gdb/blockframe.c
@ -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.
|
||||
|
92
gdb/frame.c
92
gdb/frame.c
@ -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)
|
||||
|
44
gdb/frame.h
44
gdb/frame.h
@ -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,
|
||||
|
105
gdb/stack.c
105
gdb/stack.c
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user