Convert frame unwinders to use the current frame and

"struct value".

	* frame.c (frame_debug): Make global.
	(get_frame_id): Pass this frame to unwinder routines.
	(frame_pc_unwind): Remove unused unwind->prev_pc support.
	(do_frame_register_read): Do not discard the return value of
	frame_register_read.
	(frame_register_unwind): Remove debug messages.  Use
	frame_unwind_register_value.
	(frame_unwind_register_value, get_frame_register_value): New
	functions.
	(create_new_frame, get_frame_base_address, get_frame_locals_address)
	(get_frame_args_address, get_frame_type): Pass this frame to
	unwinder routines.
	(frame_cleanup_after_sniffer, frame_prepare_for_sniffer): New
	functions.
	* frame.h: Update comments.
	(frame_debug, frame_unwind_register_value, get_frame_register_value)
	(frame_prepare_for_sniffer): Declare.
	* frame-unwind.h: Update comments and parameter names.
	(default_frame_sniffer): Declare.
	(frame_prev_register_ftype): Return a struct value *.
	(struct frame_unwind): Remove prev_pc member.
	(frame_unwind_sniffer_ftype, frame_unwind_append_sniffer): Delete.
	(frame_unwind_append_unwinder, frame_unwind_got_optimized)
	(frame_unwind_got_register, frame_unwind_got_memory)
	(frame_unwind_got_constant, frame_unwind_got_address): Declare.
	* frame-base.h: Update comments and parameter names.
	* valops.c (value_fetch_lazy): Use get_frame_register_value.  Iterate
	if necessary.  Add debugging output.
	* sentinel-frame.c (sentinel_frame_prev_register)
	(sentinel_frame_this_id): Update for new signature.
	(sentinel_frame_prev_pc): Delete.
	(sentinel_frame_unwinder): Remove prev_pc.
	* ia64-tdep.c (ia64_libunwind_frame_unwind): Do not initialize
	prev_pc.
	* libunwind-frame.c (libunwind_frame_unwind): Likewise.
	* frame-unwind.c (struct frame_unwind_table_entry): Remove sniffer.
	(frame_unwind_append_sniffer): Delete.
	(frame_unwind_append_unwinder): New function.
	(frame_unwind_find_by_frame): Take this frame.  Only use sniffers
	from unwinders.  Use frame_prepare_for_sniffer.
	(default_frame_sniffer, frame_unwind_got_optimized)
	(frame_unwind_got_register, frame_unwind_got_memory)
	(frame_unwind_got_constant, frame_unwind_got_address): New functions.
	* dummy-frame.c (dummy_frame_sniffer): Use gdbarch_dummy_id.
	(dummy_frame_prev_register, dummy_frame_this_id): Update for new
	signature.
	* gdbarch.sh: Replace unwind_dummy_id with dummy_id.
	* gdbarch.c, gdbarch.c: Regenerated.
	* frame-base.c (default_frame_base_address)
	(default_frame_locals_address, default_frame_args_address): Update
	for new signature.
	(frame_base_find_by_frame): Pass this frame to unwinder routines.
	* infcall.c (call_function_by_hand): Update comments.
	* Makefile.in (frame-unwind.o): Update dependencies.

	* gdbint.texinfo (Stack Frames): New chapter.
	(Algorithms): Move Frames text to the new chapter.
	(Target Conditionals): Delete SAVE_DUMMY_FRAME_TOS.  Document
	gdbarch_dummy_id instead of gdbarch_unwind_dummy_id.
This commit is contained in:
Daniel Jacobowitz 2008-04-30 21:16:46 +00:00
parent 9214ee5f5f
commit 669fac235d
19 changed files with 687 additions and 321 deletions

View File

@ -1,3 +1,63 @@
2008-04-30 Daniel Jacobowitz <dan@codesourcery.com>
Convert frame unwinders to use the current frame and
"struct value".
* frame.c (frame_debug): Make global.
(get_frame_id): Pass this frame to unwinder routines.
(frame_pc_unwind): Remove unused unwind->prev_pc support.
(do_frame_register_read): Do not discard the return value of
frame_register_read.
(frame_register_unwind): Remove debug messages. Use
frame_unwind_register_value.
(frame_unwind_register_value, get_frame_register_value): New
functions.
(create_new_frame, get_frame_base_address, get_frame_locals_address)
(get_frame_args_address, get_frame_type): Pass this frame to
unwinder routines.
(frame_cleanup_after_sniffer, frame_prepare_for_sniffer): New
functions.
* frame.h: Update comments.
(frame_debug, frame_unwind_register_value, get_frame_register_value)
(frame_prepare_for_sniffer): Declare.
* frame-unwind.h: Update comments and parameter names.
(default_frame_sniffer): Declare.
(frame_prev_register_ftype): Return a struct value *.
(struct frame_unwind): Remove prev_pc member.
(frame_unwind_sniffer_ftype, frame_unwind_append_sniffer): Delete.
(frame_unwind_append_unwinder, frame_unwind_got_optimized)
(frame_unwind_got_register, frame_unwind_got_memory)
(frame_unwind_got_constant, frame_unwind_got_address): Declare.
* frame-base.h: Update comments and parameter names.
* valops.c (value_fetch_lazy): Use get_frame_register_value. Iterate
if necessary. Add debugging output.
* sentinel-frame.c (sentinel_frame_prev_register)
(sentinel_frame_this_id): Update for new signature.
(sentinel_frame_prev_pc): Delete.
(sentinel_frame_unwinder): Remove prev_pc.
* ia64-tdep.c (ia64_libunwind_frame_unwind): Do not initialize
prev_pc.
* libunwind-frame.c (libunwind_frame_unwind): Likewise.
* frame-unwind.c (struct frame_unwind_table_entry): Remove sniffer.
(frame_unwind_append_sniffer): Delete.
(frame_unwind_append_unwinder): New function.
(frame_unwind_find_by_frame): Take this frame. Only use sniffers
from unwinders. Use frame_prepare_for_sniffer.
(default_frame_sniffer, frame_unwind_got_optimized)
(frame_unwind_got_register, frame_unwind_got_memory)
(frame_unwind_got_constant, frame_unwind_got_address): New functions.
* dummy-frame.c (dummy_frame_sniffer): Use gdbarch_dummy_id.
(dummy_frame_prev_register, dummy_frame_this_id): Update for new
signature.
* gdbarch.sh: Replace unwind_dummy_id with dummy_id.
* gdbarch.c, gdbarch.c: Regenerated.
* frame-base.c (default_frame_base_address)
(default_frame_locals_address, default_frame_args_address): Update
for new signature.
(frame_base_find_by_frame): Pass this frame to unwinder routines.
* infcall.c (call_function_by_hand): Update comments.
* Makefile.in (frame-unwind.o): Update dependencies.
2008-04-30 Daniel Jacobowitz <dan@codesourcery.com>
* ada-lang.c (ada_value_primitive_packed_val): Only check

View File

@ -2143,7 +2143,8 @@ frame.o: frame.c $(defs_h) $(frame_h) $(target_h) $(value_h) $(inferior_h) \
$(annotate_h) $(language_h) $(frame_unwind_h) $(frame_base_h) \
$(command_h) $(gdbcmd_h) $(observer_h) $(objfiles_h) $(exceptions_h)
frame-unwind.o: frame-unwind.c $(defs_h) $(frame_h) $(frame_unwind_h) \
$(gdb_assert_h) $(dummy_frame_h) $(gdb_obstack_h)
$(gdb_assert_h) $(dummy_frame_h) $(gdb_obstack_h) $(value_h) \
$(regcache_h)
frv-linux-tdep.o: frv-linux-tdep.c $(defs_h) $(gdbcore_h) $(target_h) \
$(frame_h) $(osabi_h) $(regcache_h) $(elf_bfd_h) $(elf_frv_h) \
$(frv_tdep_h) $(trad_frame_h) $(frame_unwind_h) $(regset_h) \

View File

@ -1,6 +1,13 @@
2008-04-30 Daniel Jacobowitz <dan@codesourcery.com>
* gdbint.texinfo (Stack Frames): New chapter.
(Algorithms): Move Frames text to the new chapter.
(Target Conditionals): Delete SAVE_DUMMY_FRAME_TOS. Document
gdbarch_dummy_id instead of gdbarch_unwind_dummy_id.
2008-04-24 Vladimir Prus <vladimir@codesourcery.com>
* doc/gdb.texinfo (GDB/MI Output Syntax): Clarify that async
* gdb.texinfo (GDB/MI Output Syntax): Clarify that async
output does not necessary include any tokens.
2008-04-22 Corinna Vinschen <vinschen@redhat.com>
@ -223,7 +230,7 @@
2007-12-17 Luis Machado <luisgpm@br.ibm.com>
* doc/gdb.texinfo: Add new parameter's description.
* gdb.texinfo: Add new parameter's description.
2007-12-16 Daniel Jacobowitz <dan@codesourcery.com>
@ -715,7 +722,7 @@
2007-02-26 Daniel Jacobowitz <dan@codesourcery.com>
* src/gdb/doc/gdb.texinfo (Standard Target Features): Mention
* gdb.texinfo (Standard Target Features): Mention
case insensitivity.
(ARM Features): Describe org.gnu.gdb.xscale.iwmmxt.
@ -744,7 +751,7 @@
(Target Description Format): Document new elements. Use
@smallexample.
(Predefined Target Types, Standard Target Features): New sections.
* doc/gdbint.texinfo (Target Descriptions): New section.
* gdbint.texinfo (Target Descriptions): New section.
2007-02-07 Daniel Jacobowitz <dan@codesourcery.com>
@ -1017,7 +1024,7 @@
2006-07-05 Daniel Jacobowitz <dan@codesourcery.com>
* doc/gdb.texinfo (KOD): Remove node.
* gdb.texinfo (KOD): Remove node.
(GDB/MI Kod Commands): Remove commented out node.
2006-07-01 Eli Zaretskii <eliz@gnu.org>

View File

@ -76,6 +76,7 @@ as the mechanisms that adapt @value{GDBN} to specific hosts and targets.
* Algorithms::
* User Interface::
* libgdb::
* Stack Frames::
* Symbol Handling::
* Language Support::
* Host Definition::
@ -273,39 +274,6 @@ cases and real-world issues. This chapter describes the basic
algorithms and mentions some of the specific target definitions that
they use.
@section Frames
@cindex frame
@cindex call stack frame
A frame is a construct that @value{GDBN} uses to keep track of calling
and called functions.
@cindex frame, unwind
@value{GDBN}'s frame model, a fresh design, was implemented with the
need to support @sc{dwarf}'s Call Frame Information in mind. In fact,
the term ``unwind'' is taken directly from that specification.
Developers wishing to learn more about unwinders, are encouraged to
read the @sc{dwarf} specification.
@findex frame_register_unwind
@findex get_frame_register
@value{GDBN}'s model is that you find a frame's registers by
``unwinding'' them from the next younger frame. That is,
@samp{get_frame_register} which returns the value of a register in
frame #1 (the next-to-youngest frame), is implemented by calling frame
#0's @code{frame_register_unwind} (the youngest frame). But then the
obvious question is: how do you access the registers of the youngest
frame itself?
@cindex sentinel frame
@findex get_frame_type
@vindex SENTINEL_FRAME
To answer this question, GDB has the @dfn{sentinel} frame, the
``-1st'' frame. Unwinding registers from the sentinel frame gives you
the current values of the youngest real frame's registers. If @var{f}
is a sentinel frame, then @code{get_frame_type (@var{f}) ==
SENTINEL_FRAME}.
@section Prologue Analysis
@cindex prologue analysis
@ -1853,6 +1821,127 @@ the query interface. Each function is parameterized by a @code{ui-out}
builder. The result of the query is constructed using that builder
before the query function returns.
@node Stack Frames
@chapter Stack Frames
@cindex frame
@cindex call stack frame
A frame is a construct that @value{GDBN} uses to keep track of calling
and called functions.
@cindex unwind frame
@value{GDBN}'s frame model, a fresh design, was implemented with the
need to support @sc{dwarf}'s Call Frame Information in mind. In fact,
the term ``unwind'' is taken directly from that specification.
Developers wishing to learn more about unwinders, are encouraged to
read the @sc{dwarf} specification, available from
@url{http://www.dwarfstd.org}.
@findex frame_register_unwind
@findex get_frame_register
@value{GDBN}'s model is that you find a frame's registers by
``unwinding'' them from the next younger frame. That is,
@samp{get_frame_register} which returns the value of a register in
frame #1 (the next-to-youngest frame), is implemented by calling frame
#0's @code{frame_register_unwind} (the youngest frame). But then the
obvious question is: how do you access the registers of the youngest
frame itself?
@cindex sentinel frame
@findex get_frame_type
@vindex SENTINEL_FRAME
To answer this question, GDB has the @dfn{sentinel} frame, the
``-1st'' frame. Unwinding registers from the sentinel frame gives you
the current values of the youngest real frame's registers. If @var{f}
is a sentinel frame, then @code{get_frame_type (@var{f}) @equiv{}
SENTINEL_FRAME}.
@section Selecting an Unwinder
@findex frame_unwind_prepend_unwinder
@findex frame_unwind_append_unwinder
The architecture registers a list of frame unwinders (@code{struct
frame_unwind}), using the functions
@code{frame_unwind_prepend_unwinder} and
@code{frame_unwind_append_unwinder}. Each unwinder includes a
sniffer. Whenever @value{GDBN} needs to unwind a frame (to fetch the
previous frame's registers or the current frame's ID), it calls
registered sniffers in order to find one which recognizes the frame.
The first time a sniffer returns non-zero, the corresponding unwinder
is assigned to the frame.
@section Unwinding the Frame ID
@cindex frame ID
Every frame has an associated ID, of type @code{struct frame_id}.
The ID includes the stack base and function start address for
the frame. The ID persists through the entire life of the frame,
including while other called frames are running; it is used to
locate an appropriate @code{struct frame_info} from the cache.
Every time the inferior stops, and at various other times, the frame
cache is flushed. Because of this, parts of @value{GDBN} which need
to keep track of individual frames cannot use pointers to @code{struct
frame_info}. A frame ID provides a stable reference to a frame, even
when the unwinder must be run again to generate a new @code{struct
frame_info} for the same frame.
The frame's unwinder's @code{this_id} method is called to find the ID.
Note that this is different from register unwinding, where the next
frame's @code{prev_register} is called to unwind this frame's
registers.
Both stack base and function address are required to identify the
frame, because a recursive function has the same function address for
two consecutive frames and a leaf function may have the same stack
address as its caller. On some platforms, a third address is part of
the ID to further disambiguate frames---for instance, on IA-64
the separate register stack address is included in the ID.
An invalid frame ID (@code{null_frame_id}) returned from the
@code{this_id} method means to stop unwinding after this frame.
@section Unwinding Registers
Each unwinder includes a @code{prev_register} method. This method
takes a frame, an associated cache pointer, and a register number.
It returns a @code{struct value *} describing the requested register,
as saved by this frame. This is the value of the register that is
current in this frame's caller.
The returned value must have the same type as the register. It may
have any lvalue type. In most circumstances one of these routines
will generate the appropriate value:
@table @code
@item frame_unwind_got_optimized
@findex frame_unwind_got_optimized
This register was not saved.
@item frame_unwind_got_register
@findex frame_unwind_got_register
This register was copied into another register in this frame. This
is also used for unchanged registers; they are ``copied'' into the
same register.
@item frame_unwind_got_memory
@findex frame_unwind_got_memory
This register was saved in memory.
@item frame_unwind_got_constant
@findex frame_unwind_got_constant
This register was not saved, but the unwinder can compute the previous
value some other way.
@item frame_unwind_got_address
@findex frame_unwind_got_address
Same as @code{frame_unwind_got_constant}, except that the value is a target
address. This is frequently used for the stack pointer, which is not
explicitly saved but has a known offset from this frame's stack
pointer. For architectures with a flat unified address space, this is
generally the same as @code{frame_unwind_got_constant}.
@end table
@node Symbol Handling
@chapter Symbol Handling
@ -3943,14 +4032,6 @@ This method replaces @w{@code{gdbarch_call_dummy_location (@var{gdbarch})}} and
Return the name of register @var{regnr} as a string. May return @code{NULL}
to indicate that @var{regnr} is not a valid register.
@item SAVE_DUMMY_FRAME_TOS (@var{sp})
@findex SAVE_DUMMY_FRAME_TOS
@anchor{SAVE_DUMMY_FRAME_TOS} Used in @samp{call_function_by_hand} to
notify the target dependent code of the top-of-stack value that will be
passed to the inferior code. This is the value of the @code{SP}
after both the dummy frame and space for parameters/results have been
allocated on the stack. @xref{gdbarch_unwind_dummy_id}.
@item int gdbarch_sdb_reg_to_regnum (@var{gdbarch}, @var{sdb_regnr})
@findex gdbarch_sdb_reg_to_regnum
Use this function to convert sdb register @var{sdb_regnr} into @value{GDBN}
@ -4132,13 +4213,12 @@ the @code{opcodes} library (@pxref{Support Libraries, ,Opcodes}).
@file{include/dis-asm.h} used to pass information to the instruction
decoding routine.
@item frame_id gdbarch_unwind_dummy_id (@var{gdbarch}, @var{frame})
@findex gdbarch_unwind_dummy_id
@anchor{gdbarch_unwind_dummy_id} Given @var{frame} return a @w{@code{struct
@item frame_id gdbarch_dummy_id (@var{gdbarch}, @var{frame})
@findex gdbarch_dummy_id
@anchor{gdbarch_dummy_id} Given @var{frame} return a @w{@code{struct
frame_id}} that uniquely identifies an inferior function call's dummy
frame. The value returned must match the dummy frame stack value
previously saved using @code{SAVE_DUMMY_FRAME_TOS}.
@xref{SAVE_DUMMY_FRAME_TOS}.
previously saved by @code{call_function_by_hand}.
@item DEPRECATED_USE_STRUCT_CONVENTION (@var{gcc_p}, @var{type})
@findex DEPRECATED_USE_STRUCT_CONVENTION

View File

@ -39,7 +39,7 @@ struct dummy_frame
{
struct dummy_frame *next;
/* This frame's ID. Must match the value returned by
gdbarch_unwind_dummy_id. */
gdbarch_dummy_id. */
struct frame_id id;
/* The caller's regcache. */
struct regcache *regcache;
@ -124,7 +124,7 @@ struct dummy_frame_cache
int
dummy_frame_sniffer (const struct frame_unwind *self,
struct frame_info *next_frame,
struct frame_info *this_frame,
void **this_prologue_cache)
{
struct dummy_frame *dummyframe;
@ -141,12 +141,9 @@ dummy_frame_sniffer (const struct frame_unwind *self,
/* Don't bother unles there is at least one dummy frame. */
if (dummy_frame_stack != NULL)
{
/* Use an architecture specific method to extract the prev's
dummy ID from the next frame. Note that this method uses
frame_register_unwind to obtain the register values needed to
determine the dummy frame's ID. */
this_id = gdbarch_unwind_dummy_id (get_frame_arch (next_frame),
next_frame);
/* Use an architecture specific method to extract this frame's
dummy ID, assuming it is a dummy frame. */
this_id = gdbarch_dummy_id (get_frame_arch (this_frame), this_frame);
/* Use that ID to find the corresponding cache entry. */
for (dummyframe = dummy_frame_stack;
@ -170,43 +167,37 @@ dummy_frame_sniffer (const struct frame_unwind *self,
/* 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
dummy_frame_prev_register (struct frame_info *next_frame,
static struct value *
dummy_frame_prev_register (struct frame_info *this_frame,
void **this_prologue_cache,
int regnum, int *optimized,
enum lval_type *lvalp, CORE_ADDR *addrp,
int *realnum, gdb_byte *bufferp)
int regnum)
{
/* The dummy-frame sniffer always fills in the cache. */
struct dummy_frame_cache *cache = (*this_prologue_cache);
struct gdbarch *gdbarch = get_frame_arch (this_frame);
struct value *reg_val;
/* The dummy-frame sniffer always fills in the cache. */
gdb_assert (cache != NULL);
/* 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;
reg_val = value_zero (register_type (gdbarch, regnum), not_lval);
/* If needed, find and return the value of the register. */
if (bufferp != NULL)
{
/* Return the actual value. */
/* Use the regcache_cooked_read() method so that it, on the fly,
constructs either a raw or pseudo register from the raw
register cache. */
regcache_cooked_read (cache->prev_regcache, regnum, bufferp);
}
/* Use the regcache_cooked_read() method so that it, on the fly,
constructs either a raw or pseudo register from the raw
register cache. */
regcache_cooked_read (cache->prev_regcache, regnum,
value_contents_writeable (reg_val));
return reg_val;
}
/* Assuming that THIS frame is a dummy (remember, the NEXT and not
THIS frame is passed in), return the ID of THIS frame. That ID is
/* Assuming that THIS frame is a dummy, return the ID of THIS frame. That ID is
determined by examining the NEXT frame's unwound registers using
the method unwind_dummy_id(). As a side effect, THIS dummy frame's
the method dummy_id(). As a side effect, THIS dummy frame's
dummy cache is located and and saved in THIS_PROLOGUE_CACHE. */
static void
dummy_frame_this_id (struct frame_info *next_frame,
dummy_frame_this_id (struct frame_info *this_frame,
void **this_prologue_cache,
struct frame_id *this_id)
{

View File

@ -28,22 +28,21 @@
really need to override this. */
static CORE_ADDR
default_frame_base_address (struct frame_info *next_frame, void **this_cache)
default_frame_base_address (struct frame_info *this_frame, void **this_cache)
{
struct frame_info *this_frame = get_prev_frame (next_frame);
return get_frame_base (this_frame); /* sigh! */
}
static CORE_ADDR
default_frame_locals_address (struct frame_info *next_frame, void **this_cache)
default_frame_locals_address (struct frame_info *this_frame, void **this_cache)
{
return default_frame_base_address (next_frame, this_cache);
return default_frame_base_address (this_frame, this_cache);
}
static CORE_ADDR
default_frame_args_address (struct frame_info *next_frame, void **this_cache)
default_frame_args_address (struct frame_info *this_frame, void **this_cache)
{
return default_frame_base_address (next_frame, this_cache);
return default_frame_base_address (this_frame, this_cache);
}
const struct frame_base default_frame_base = {
@ -97,16 +96,16 @@ frame_base_set_default (struct gdbarch *gdbarch,
}
const struct frame_base *
frame_base_find_by_frame (struct frame_info *next_frame)
frame_base_find_by_frame (struct frame_info *this_frame)
{
struct gdbarch *gdbarch = get_frame_arch (next_frame);
struct gdbarch *gdbarch = get_frame_arch (this_frame);
struct frame_base_table *table = gdbarch_data (gdbarch, frame_base_data);
struct frame_base_table_entry *entry;
for (entry = table->head; entry != NULL; entry = entry->next)
{
const struct frame_base *desc = NULL;
desc = entry->sniffer (next_frame);
desc = entry->sniffer (this_frame);
if (desc != NULL)
return desc;
}

View File

@ -28,9 +28,9 @@ struct gdbarch;
struct regcache;
/* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
and that this is a `normal frame'; use the NEXT frame, and its
register unwind method, to determine the address of THIS frame's
`base'.
and that this is a `normal frame'; use THIS frame, and implicitly
the NEXT frame's register unwind method, to determine the address
of THIS frame's `base'.
The exact meaning of `base' is highly dependant on the type of the
debug info. It is assumed that dwarf2, stabs, ... will each
@ -42,17 +42,17 @@ struct regcache;
/* A generic base address. */
typedef CORE_ADDR (frame_this_base_ftype) (struct frame_info *next_frame,
typedef CORE_ADDR (frame_this_base_ftype) (struct frame_info *this_frame,
void **this_base_cache);
/* The base address of the frame's local variables. */
typedef CORE_ADDR (frame_this_locals_ftype) (struct frame_info *next_frame,
typedef CORE_ADDR (frame_this_locals_ftype) (struct frame_info *this_frame,
void **this_base_cache);
/* The base address of the frame's arguments / parameters. */
typedef CORE_ADDR (frame_this_args_ftype) (struct frame_info *next_frame,
typedef CORE_ADDR (frame_this_args_ftype) (struct frame_info *this_frame,
void **this_base_cache);
struct frame_base
@ -65,10 +65,10 @@ struct frame_base
frame_this_args_ftype *this_args;
};
/* Given the NEXT frame, return the frame base methods for THIS frame,
/* Given THIS frame, return the frame base methods for THIS frame,
or NULL if it can't handle THIS frame. */
typedef const struct frame_base *(frame_base_sniffer_ftype) (struct frame_info *next_frame);
typedef const struct frame_base *(frame_base_sniffer_ftype) (struct frame_info *this_frame);
/* Append a frame base sniffer to the list. The sniffers are polled
in the order that they are appended. */
@ -86,6 +86,6 @@ extern void frame_base_set_default (struct gdbarch *gdbarch,
/* Iterate through the list of frame base handlers until one returns
an implementation. */
extern const struct frame_base *frame_base_find_by_frame (struct frame_info *next_frame);
extern const struct frame_base *frame_base_find_by_frame (struct frame_info *this_frame);
#endif

View File

@ -20,15 +20,17 @@
#include "defs.h"
#include "frame.h"
#include "frame-unwind.h"
#include "gdb_assert.h"
#include "dummy-frame.h"
#include "value.h"
#include "regcache.h"
#include "gdb_assert.h"
#include "gdb_obstack.h"
static struct gdbarch_data *frame_unwind_data;
struct frame_unwind_table_entry
{
frame_unwind_sniffer_ftype *sniffer;
const struct frame_unwind *unwinder;
struct frame_unwind_table_entry *next;
};
@ -54,19 +56,6 @@ frame_unwind_init (struct obstack *obstack)
return table;
}
void
frame_unwind_append_sniffer (struct gdbarch *gdbarch,
frame_unwind_sniffer_ftype *sniffer)
{
struct frame_unwind_table *table = gdbarch_data (gdbarch, frame_unwind_data);
struct frame_unwind_table_entry **ip;
/* Find the end of the list and insert the new entry there. */
for (ip = table->osabi_head; (*ip) != NULL; ip = &(*ip)->next);
(*ip) = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct frame_unwind_table_entry);
(*ip)->sniffer = sniffer;
}
void
frame_unwind_prepend_unwinder (struct gdbarch *gdbarch,
const struct frame_unwind *unwinder)
@ -81,32 +70,123 @@ frame_unwind_prepend_unwinder (struct gdbarch *gdbarch,
(*table->osabi_head) = entry;
}
void
frame_unwind_append_unwinder (struct gdbarch *gdbarch,
const struct frame_unwind *unwinder)
{
struct frame_unwind_table *table = gdbarch_data (gdbarch, frame_unwind_data);
struct frame_unwind_table_entry **ip;
/* Find the end of the list and insert the new entry there. */
for (ip = table->osabi_head; (*ip) != NULL; ip = &(*ip)->next);
(*ip) = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct frame_unwind_table_entry);
(*ip)->unwinder = unwinder;
}
const struct frame_unwind *
frame_unwind_find_by_frame (struct frame_info *next_frame, void **this_cache)
frame_unwind_find_by_frame (struct frame_info *this_frame, void **this_cache)
{
int i;
struct gdbarch *gdbarch = get_frame_arch (next_frame);
struct gdbarch *gdbarch = get_frame_arch (this_frame);
struct frame_unwind_table *table = gdbarch_data (gdbarch, frame_unwind_data);
struct frame_unwind_table_entry *entry;
struct cleanup *old_cleanup;
for (entry = table->list; entry != NULL; entry = entry->next)
{
if (entry->sniffer != NULL)
struct cleanup *old_cleanup;
old_cleanup = frame_prepare_for_sniffer (this_frame, entry->unwinder);
if (entry->unwinder->sniffer (entry->unwinder, this_frame,
this_cache))
{
const struct frame_unwind *desc = NULL;
desc = entry->sniffer (next_frame);
if (desc != NULL)
return desc;
}
if (entry->unwinder != NULL)
{
if (entry->unwinder->sniffer (entry->unwinder, next_frame,
this_cache))
return entry->unwinder;
discard_cleanups (old_cleanup);
return entry->unwinder;
}
do_cleanups (old_cleanup);
}
internal_error (__FILE__, __LINE__, _("frame_unwind_find_by_frame failed"));
}
/* A default frame sniffer which always accepts the frame. Used by
fallback prologue unwinders. */
int
default_frame_sniffer (const struct frame_unwind *self,
struct frame_info *this_frame,
void **this_prologue_cache)
{
return 1;
}
/* Helper functions for value-based register unwinding. These return
a (possibly lazy) value of the appropriate type. */
/* Return a value which indicates that FRAME did not save REGNUM. */
struct value *
frame_unwind_got_optimized (struct frame_info *frame, int regnum)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
struct value *reg_val;
reg_val = value_zero (register_type (gdbarch, regnum), not_lval);
set_value_optimized_out (reg_val, 1);
return reg_val;
}
/* Return a value which indicates that FRAME copied REGNUM into
register NEW_REGNUM. */
struct value *
frame_unwind_got_register (struct frame_info *frame, int regnum, int new_regnum)
{
return value_of_register_lazy (frame, new_regnum);
}
/* Return a value which indicates that FRAME saved REGNUM in memory at
ADDR. */
struct value *
frame_unwind_got_memory (struct frame_info *frame, int regnum, CORE_ADDR addr)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
return value_at_lazy (register_type (gdbarch, regnum), addr);
}
/* Return a value which indicates that FRAME's saved version of
REGNUM has a known constant (computed) value of VAL. */
struct value *
frame_unwind_got_constant (struct frame_info *frame, int regnum,
ULONGEST val)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
struct value *reg_val;
reg_val = value_zero (register_type (gdbarch, regnum), not_lval);
store_unsigned_integer (value_contents_writeable (reg_val),
register_size (gdbarch, regnum), val);
return reg_val;
}
/* Return a value which indicates that FRAME's saved version of REGNUM
has a known constant (computed) value of ADDR. Convert the
CORE_ADDR to a target address if necessary. */
struct value *
frame_unwind_got_address (struct frame_info *frame, int regnum,
CORE_ADDR addr)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
struct value *reg_val;
reg_val = value_zero (register_type (gdbarch, regnum), not_lval);
pack_long (value_contents_writeable (reg_val),
register_type (gdbarch, regnum), addr);
return reg_val;
}
extern initialize_file_ftype _initialize_frame_unwind; /* -Wmissing-prototypes */
void

View File

@ -26,6 +26,7 @@ struct frame_id;
struct frame_unwind;
struct gdbarch;
struct regcache;
struct value;
#include "frame.h" /* For enum frame_type. */
@ -41,17 +42,24 @@ struct regcache;
as where this frame's prologue stores the previous frame's
registers. */
/* Given the NEXT frame, take a wiff of THIS frame's registers (namely
/* Given THIS frame, take a whiff of its registers (namely
the PC and attributes) and if SELF is the applicable unwinder,
return non-zero. Possibly also initialize THIS_PROLOGUE_CACHE. */
typedef int (frame_sniffer_ftype) (const struct frame_unwind *self,
struct frame_info *next_frame,
struct frame_info *this_frame,
void **this_prologue_cache);
/* A default frame sniffer which always accepts the frame. Used by
fallback prologue unwinders. */
int default_frame_sniffer (const struct frame_unwind *self,
struct frame_info *this_frame,
void **this_prologue_cache);
/* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
use the NEXT frame, and its register unwind method, to determine
the frame ID of THIS frame.
use THIS frame, and through it the NEXT frame's register unwind
method, to determine the frame ID of THIS frame.
A frame ID provides an invariant that can be used to re-identify an
instance of a frame. It is a combination of the frame's `base' and
@ -72,14 +80,14 @@ typedef int (frame_sniffer_ftype) (const struct frame_unwind *self,
with the other unwind methods. Memory for that cache should be
allocated using FRAME_OBSTACK_ZALLOC(). */
typedef void (frame_this_id_ftype) (struct frame_info *next_frame,
typedef void (frame_this_id_ftype) (struct frame_info *this_frame,
void **this_prologue_cache,
struct frame_id *this_id);
/* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
use the NEXT frame, and its register unwind method, to unwind THIS
frame's registers (returning the value of the specified register
REGNUM in the previous frame).
use THIS frame, and implicitly the NEXT frame's register unwind
method, to unwind THIS frame's registers (returning the value of
the specified register REGNUM in the previous frame).
Traditionally, THIS frame's registers were unwound by examining
THIS frame's function's prologue and identifying which registers
@ -91,37 +99,22 @@ typedef void (frame_this_id_ftype) (struct frame_info *next_frame,
register in the previous frame is found in memory at SP+12, and
THIS frame's SP can be obtained by unwinding the NEXT frame's SP.
Why not pass in THIS_FRAME? By passing in NEXT frame and THIS
cache, the supplied parameters are consistent with the sibling
function THIS_ID.
This function takes THIS_FRAME as an argument. It can find the
values of registers in THIS frame by calling get_frame_register
(THIS_FRAME), and reinvoke itself to find other registers in the
PREVIOUS frame by calling frame_unwind_register (THIS_FRAME).
Can the code call ``frame_register (get_prev_frame (NEXT_FRAME))''?
Won't the call frame_register (THIS_FRAME) be faster? Well,
ignoring the possability that the previous frame does not yet
exist, the ``frame_register (FRAME)'' function is expanded to
``frame_register_unwind (get_next_frame (FRAME)'' and hence that
call will expand to ``frame_register_unwind (get_next_frame
(get_prev_frame (NEXT_FRAME)))''. Might as well call
``frame_register_unwind (NEXT_FRAME)'' directly.
The result is a GDB value object describing the register value. It
may be a lazy reference to memory, a lazy reference to the value of
a register in THIS frame, or a non-lvalue.
THIS_PROLOGUE_CACHE can be used to share any prolog analysis data
with the other unwind methods. Memory for that cache should be
allocated using FRAME_OBSTACK_ZALLOC(). */
typedef void (frame_prev_register_ftype) (struct frame_info *next_frame,
void **this_prologue_cache,
int prev_regnum,
int *optimized,
enum lval_type * lvalp,
CORE_ADDR *addrp,
int *realnump, gdb_byte *valuep);
/* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
use the NEXT frame, and its register unwind method, to return the PREV
frame's program-counter. */
typedef CORE_ADDR (frame_prev_pc_ftype) (struct frame_info *next_frame,
void **this_prologue_cache);
typedef struct value * (frame_prev_register_ftype)
(struct frame_info *this_frame, void **this_prologue_cache,
int regnum);
/* Deallocate extra memory associated with the frame cache if any. */
@ -139,7 +132,6 @@ struct frame_unwind
frame_prev_register_ftype *prev_register;
const struct frame_data *unwind_data;
frame_sniffer_ftype *sniffer;
frame_prev_pc_ftype *prev_pc;
frame_dealloc_cache_ftype *dealloc_cache;
};
@ -152,23 +144,50 @@ struct frame_unwind
extern void frame_unwind_prepend_unwinder (struct gdbarch *gdbarch,
const struct frame_unwind *unwinder);
/* Given the NEXT frame, take a wiff of THIS frame's registers (namely
the PC and attributes) and if it is the applicable unwinder return
the unwind methods, or NULL if it is not. */
typedef const struct frame_unwind *(frame_unwind_sniffer_ftype) (struct frame_info *next_frame);
/* Add a frame sniffer to the list. The predicates are polled in the
order that they are appended. The initial list contains the dummy
frame sniffer. */
extern void frame_unwind_append_sniffer (struct gdbarch *gdbarch,
frame_unwind_sniffer_ftype *sniffer);
extern void frame_unwind_append_unwinder (struct gdbarch *gdbarch,
const struct frame_unwind *unwinder);
/* Iterate through the next frame's sniffers until one returns with an
/* Iterate through sniffers for THIS frame until one returns with an
unwinder implementation. Possibly initialize THIS_CACHE. */
extern const struct frame_unwind *frame_unwind_find_by_frame (struct frame_info *next_frame,
extern const struct frame_unwind *frame_unwind_find_by_frame (struct frame_info *this_frame,
void **this_cache);
/* Helper functions for value-based register unwinding. These return
a (possibly lazy) value of the appropriate type. */
/* Return a value which indicates that FRAME did not save REGNUM. */
struct value *frame_unwind_got_optimized (struct frame_info *frame,
int regnum);
/* Return a value which indicates that FRAME copied REGNUM into
register NEW_REGNUM. */
struct value *frame_unwind_got_register (struct frame_info *frame, int regnum,
int new_regnum);
/* Return a value which indicates that FRAME saved REGNUM in memory at
ADDR. */
struct value *frame_unwind_got_memory (struct frame_info *frame, int regnum,
CORE_ADDR addr);
/* Return a value which indicates that FRAME's saved version of
REGNUM has a known constant (computed) value of VAL. */
struct value *frame_unwind_got_constant (struct frame_info *frame, int regnum,
ULONGEST val);
/* Return a value which indicates that FRAME's saved version of REGNUM
has a known constant (computed) value of ADDR. Convert the
CORE_ADDR to a target address if necessary. */
struct value *frame_unwind_got_address (struct frame_info *frame, int regnum,
CORE_ADDR addr);
#endif

View File

@ -113,7 +113,7 @@ struct frame_info
/* Flag to control debugging. */
static int frame_debug;
int frame_debug;
static void
show_frame_debug (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
@ -255,10 +255,9 @@ get_frame_id (struct frame_info *fi)
fi->level);
/* Find the unwinder. */
if (fi->unwind == NULL)
fi->unwind = frame_unwind_find_by_frame (fi->next,
&fi->prologue_cache);
fi->unwind = frame_unwind_find_by_frame (fi, &fi->prologue_cache);
/* Find THIS frame's ID. */
fi->unwind->this_id (fi->next, &fi->prologue_cache, &fi->this_id.value);
fi->unwind->this_id (fi, &fi->prologue_cache, &fi->this_id.value);
fi->this_id.p = 1;
if (frame_debug)
{
@ -427,15 +426,7 @@ frame_pc_unwind (struct frame_info *this_frame)
if (!this_frame->prev_pc.p)
{
CORE_ADDR pc;
if (this_frame->unwind == NULL)
this_frame->unwind
= frame_unwind_find_by_frame (this_frame->next,
&this_frame->prologue_cache);
if (this_frame->unwind->prev_pc != NULL)
/* A per-frame unwinder, prefer it. */
pc = this_frame->unwind->prev_pc (this_frame->next,
&this_frame->prologue_cache);
else if (gdbarch_unwind_pc_p (get_frame_arch (this_frame)))
if (gdbarch_unwind_pc_p (get_frame_arch (this_frame)))
{
/* The right way. The `pure' way. The one true way. This
method depends solely on the register-unwind code to
@ -495,8 +486,7 @@ get_frame_func (struct frame_info *fi)
static int
do_frame_register_read (void *src, int regnum, gdb_byte *buf)
{
frame_register_read (src, regnum, buf);
return 1;
return frame_register_read (src, regnum, buf);
}
struct regcache *
@ -552,15 +542,7 @@ frame_register_unwind (struct frame_info *frame, int regnum,
int *optimizedp, enum lval_type *lvalp,
CORE_ADDR *addrp, int *realnump, gdb_byte *bufferp)
{
struct frame_unwind_cache *cache;
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog, "\
{ frame_register_unwind (frame=%d,regnum=%d(%s),...) ",
frame->level, regnum,
frame_map_regnum_to_name (frame, regnum));
}
struct value *value;
/* Require all but BUFFERP to be valid. A NULL BUFFERP indicates
that the value proper does not need to be fetched. */
@ -570,43 +552,23 @@ frame_register_unwind (struct frame_info *frame, int regnum,
gdb_assert (realnump != NULL);
/* gdb_assert (bufferp != NULL); */
/* NOTE: cagney/2002-11-27: A program trying to unwind a NULL frame
is broken. There is always a frame. If there, for some reason,
isn't a frame, there is some pretty busted code as it should have
detected the problem before calling here. */
gdb_assert (frame != NULL);
value = frame_unwind_register_value (frame, regnum);
/* Find the unwinder. */
if (frame->unwind == NULL)
frame->unwind = frame_unwind_find_by_frame (frame->next,
&frame->prologue_cache);
gdb_assert (value != NULL);
/* Ask this frame to unwind its register. See comment in
"frame-unwind.h" for why NEXT frame and this unwind cache are
passed in. */
frame->unwind->prev_register (frame->next, &frame->prologue_cache, regnum,
optimizedp, lvalp, addrp, realnump, bufferp);
*optimizedp = value_optimized_out (value);
*lvalp = VALUE_LVAL (value);
*addrp = VALUE_ADDRESS (value);
*realnump = VALUE_REGNUM (value);
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog, "->");
fprintf_unfiltered (gdb_stdlog, " *optimizedp=%d", (*optimizedp));
fprintf_unfiltered (gdb_stdlog, " *lvalp=%d", (int) (*lvalp));
fprintf_unfiltered (gdb_stdlog, " *addrp=0x%s", paddr_nz ((*addrp)));
fprintf_unfiltered (gdb_stdlog, " *bufferp=");
if (bufferp == NULL)
fprintf_unfiltered (gdb_stdlog, "<NULL>");
else
{
int i;
const unsigned char *buf = bufferp;
fprintf_unfiltered (gdb_stdlog, "[");
for (i = 0; i < register_size (get_frame_arch (frame), regnum); i++)
fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]);
fprintf_unfiltered (gdb_stdlog, "]");
}
fprintf_unfiltered (gdb_stdlog, " }\n");
}
if (bufferp)
memcpy (bufferp, value_contents_all (value),
TYPE_LENGTH (value_type (value)));
/* Dispose of the new value. This prevents watchpoints from
trying to watch the saved frame pointer. */
release_value (value);
value_free (value);
}
void
@ -647,6 +609,71 @@ get_frame_register (struct frame_info *frame,
frame_unwind_register (frame->next, regnum, buf);
}
struct value *
frame_unwind_register_value (struct frame_info *frame, int regnum)
{
struct value *value;
gdb_assert (frame != NULL);
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog, "\
{ frame_unwind_register_value (frame=%d,regnum=%d(%s),...) ",
frame->level, regnum,
frame_map_regnum_to_name (frame, regnum));
}
/* Find the unwinder. */
if (frame->unwind == NULL)
frame->unwind = frame_unwind_find_by_frame (frame, &frame->prologue_cache);
/* Ask this frame to unwind its register. */
value = frame->unwind->prev_register (frame, &frame->prologue_cache, regnum);
if (frame_debug)
{
fprintf_unfiltered (gdb_stdlog, "->");
if (value_optimized_out (value))
fprintf_unfiltered (gdb_stdlog, " optimized out");
else
{
if (VALUE_LVAL (value) == lval_register)
fprintf_unfiltered (gdb_stdlog, " register=%d",
VALUE_REGNUM (value));
else if (VALUE_LVAL (value) == lval_memory)
fprintf_unfiltered (gdb_stdlog, " address=0x%s",
paddr_nz (VALUE_ADDRESS (value)));
else
fprintf_unfiltered (gdb_stdlog, " computed");
if (value_lazy (value))
fprintf_unfiltered (gdb_stdlog, " lazy");
else
{
int i;
const gdb_byte *buf = value_contents (value);
fprintf_unfiltered (gdb_stdlog, " bytes=");
fprintf_unfiltered (gdb_stdlog, "[");
for (i = 0; i < register_size (get_frame_arch (frame), regnum); i++)
fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]);
fprintf_unfiltered (gdb_stdlog, "]");
}
}
fprintf_unfiltered (gdb_stdlog, " }\n");
}
return value;
}
struct value *
get_frame_register_value (struct frame_info *frame, int regnum)
{
return frame_unwind_register_value (frame->next, regnum);
}
LONGEST
frame_unwind_register_signed (struct frame_info *frame, int regnum)
{
@ -1022,7 +1049,7 @@ create_new_frame (CORE_ADDR addr, CORE_ADDR pc)
/* Select/initialize both the unwind function and the frame's type
based on the PC. */
fi->unwind = frame_unwind_find_by_frame (fi->next, &fi->prologue_cache);
fi->unwind = frame_unwind_find_by_frame (fi, &fi->prologue_cache);
fi->this_id.p = 1;
deprecated_update_frame_base_hack (fi, addr);
@ -1569,8 +1596,8 @@ get_frame_base_address (struct frame_info *fi)
/* Sneaky: If the low-level unwind and high-level base code share a
common unwinder, let them share the prologue cache. */
if (fi->base->unwind == fi->unwind)
return fi->base->this_base (fi->next, &fi->prologue_cache);
return fi->base->this_base (fi->next, &fi->base_cache);
return fi->base->this_base (fi, &fi->prologue_cache);
return fi->base->this_base (fi, &fi->base_cache);
}
CORE_ADDR
@ -1585,10 +1612,8 @@ get_frame_locals_address (struct frame_info *fi)
/* Sneaky: If the low-level unwind and high-level base code share a
common unwinder, let them share the prologue cache. */
if (fi->base->unwind == fi->unwind)
cache = &fi->prologue_cache;
else
cache = &fi->base_cache;
return fi->base->this_locals (fi->next, cache);
return fi->base->this_locals (fi, &fi->prologue_cache);
return fi->base->this_locals (fi, &fi->base_cache);
}
CORE_ADDR
@ -1603,10 +1628,8 @@ get_frame_args_address (struct frame_info *fi)
/* Sneaky: If the low-level unwind and high-level base code share a
common unwinder, let them share the prologue cache. */
if (fi->base->unwind == fi->unwind)
cache = &fi->prologue_cache;
else
cache = &fi->base_cache;
return fi->base->this_args (fi->next, cache);
return fi->base->this_args (fi, &fi->prologue_cache);
return fi->base->this_args (fi, &fi->base_cache);
}
/* Level of the selected frame: 0 for innermost, 1 for its caller, ...
@ -1627,8 +1650,7 @@ get_frame_type (struct frame_info *frame)
if (frame->unwind == NULL)
/* Initialize the frame's unwinder because that's what
provides the frame's type. */
frame->unwind = frame_unwind_find_by_frame (frame->next,
&frame->prologue_cache);
frame->unwind = frame_unwind_find_by_frame (frame, &frame->prologue_cache);
return frame->unwind->type;
}
@ -1769,6 +1791,50 @@ frame_stop_reason_string (enum unwind_stop_reason reason)
}
}
/* Clean up after a failed (wrong unwinder) attempt to unwind past
FRAME. */
static void
frame_cleanup_after_sniffer (void *arg)
{
struct frame_info *frame = arg;
/* The sniffer should not allocate a prologue cache if it did not
match this frame. */
gdb_assert (frame->prologue_cache == NULL);
/* No sniffer should extend the frame chain; sniff based on what is
already certain. */
gdb_assert (!frame->prev_p);
/* The sniffer should not check the frame's ID; that's circular. */
gdb_assert (!frame->this_id.p);
/* Clear cached fields dependent on the unwinder.
The previous PC is independent of the unwinder, but the previous
function is not (see frame_unwind_address_in_block). */
frame->prev_func.p = 0;
frame->prev_func.addr = 0;
/* Discard the unwinder last, so that we can easily find it if an assertion
in this function triggers. */
frame->unwind = NULL;
}
/* Set FRAME's unwinder temporarily, so that we can call a sniffer.
Return a cleanup which should be called if unwinding fails, and
discarded if it succeeds. */
struct cleanup *
frame_prepare_for_sniffer (struct frame_info *frame,
const struct frame_unwind *unwind)
{
gdb_assert (frame->unwind == NULL);
frame->unwind = unwind;
return make_cleanup (frame_cleanup_after_sniffer, frame);
}
extern initialize_file_ftype _initialize_frame; /* -Wmissing-prototypes */
static struct cmd_list_element *set_backtrace_cmdlist;

View File

@ -144,6 +144,10 @@ struct frame_id
/* For convenience. All fields are zero. */
extern const struct frame_id null_frame_id;
/* Flag to control debugging. */
extern int frame_debug;
/* Construct a frame ID. The first parameter is the frame's constant
stack address (typically the outer-bound), and the second the
frame's constant code address (typically the entry point).
@ -460,13 +464,19 @@ extern void frame_register_unwind (struct frame_info *frame, int regnum,
/* Fetch a register from this, or unwind a register from the next
frame. Note that the get_frame methods are wrappers to
frame->next->unwind. They all [potentially] throw an error if the
fetch fails. */
fetch fails. The value methods never return NULL, but usually
do return a lazy value. */
extern void frame_unwind_register (struct frame_info *frame,
int regnum, gdb_byte *buf);
extern void get_frame_register (struct frame_info *frame,
int regnum, gdb_byte *buf);
struct value *frame_unwind_register_value (struct frame_info *frame,
int regnum);
struct value *get_frame_register_value (struct frame_info *frame,
int regnum);
extern LONGEST frame_unwind_register_signed (struct frame_info *frame,
int regnum);
extern LONGEST get_frame_register_signed (struct frame_info *frame,
@ -666,6 +676,12 @@ extern void (*deprecated_selected_frame_level_changed_hook) (int);
extern void return_command (char *, int);
/* Set FRAME's unwinder temporarily, so that we can call a sniffer.
Return a cleanup which should be called if unwinding fails, and
discarded if it succeeds. */
struct cleanup *frame_prepare_for_sniffer (struct frame_info *frame,
const struct frame_unwind *unwind);
/* Notes (cagney/2002-11-27, drow/2003-09-06):

View File

@ -162,7 +162,7 @@ struct gdbarch
gdbarch_dwarf2_reg_to_regnum_ftype *dwarf2_reg_to_regnum;
gdbarch_register_name_ftype *register_name;
gdbarch_register_type_ftype *register_type;
gdbarch_unwind_dummy_id_ftype *unwind_dummy_id;
gdbarch_dummy_id_ftype *dummy_id;
int deprecated_fp_regnum;
gdbarch_push_dummy_call_ftype *push_dummy_call;
int call_dummy_location;
@ -284,7 +284,7 @@ struct gdbarch startup_gdbarch =
no_op_reg_to_regnum, /* dwarf2_reg_to_regnum */
0, /* register_name */
0, /* register_type */
0, /* unwind_dummy_id */
0, /* dummy_id */
-1, /* deprecated_fp_regnum */
0, /* push_dummy_call */
0, /* call_dummy_location */
@ -522,7 +522,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
if (gdbarch->register_name == 0)
fprintf_unfiltered (log, "\n\tregister_name");
/* Skip verify of register_type, has predicate */
/* Skip verify of unwind_dummy_id, has predicate */
/* Skip verify of dummy_id, has predicate */
/* Skip verify of deprecated_fp_regnum, invalid_p == 0 */
/* Skip verify of push_dummy_call, has predicate */
/* Skip verify of call_dummy_location, invalid_p == 0 */
@ -714,6 +714,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
fprintf_unfiltered (file,
"gdbarch_dump: double_format = %s\n",
pformat (gdbarch->double_format));
fprintf_unfiltered (file,
"gdbarch_dump: gdbarch_dummy_id_p() = %d\n",
gdbarch_dummy_id_p (gdbarch));
fprintf_unfiltered (file,
"gdbarch_dump: dummy_id = <0x%lx>\n",
(long) gdbarch->dummy_id);
fprintf_unfiltered (file,
"gdbarch_dump: dwarf2_reg_to_regnum = <0x%lx>\n",
(long) gdbarch->dwarf2_reg_to_regnum);
@ -978,12 +984,6 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
fprintf_unfiltered (file,
"gdbarch_dump: target_desc = %s\n",
paddr_d ((long) gdbarch->target_desc));
fprintf_unfiltered (file,
"gdbarch_dump: gdbarch_unwind_dummy_id_p() = %d\n",
gdbarch_unwind_dummy_id_p (gdbarch));
fprintf_unfiltered (file,
"gdbarch_dump: unwind_dummy_id = <0x%lx>\n",
(long) gdbarch->unwind_dummy_id);
fprintf_unfiltered (file,
"gdbarch_dump: gdbarch_unwind_pc_p() = %d\n",
gdbarch_unwind_pc_p (gdbarch));
@ -1646,27 +1646,27 @@ set_gdbarch_register_type (struct gdbarch *gdbarch,
}
int
gdbarch_unwind_dummy_id_p (struct gdbarch *gdbarch)
gdbarch_dummy_id_p (struct gdbarch *gdbarch)
{
gdb_assert (gdbarch != NULL);
return gdbarch->unwind_dummy_id != NULL;
return gdbarch->dummy_id != NULL;
}
struct frame_id
gdbarch_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *info)
gdbarch_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
{
gdb_assert (gdbarch != NULL);
gdb_assert (gdbarch->unwind_dummy_id != NULL);
gdb_assert (gdbarch->dummy_id != NULL);
if (gdbarch_debug >= 2)
fprintf_unfiltered (gdb_stdlog, "gdbarch_unwind_dummy_id called\n");
return gdbarch->unwind_dummy_id (gdbarch, info);
fprintf_unfiltered (gdb_stdlog, "gdbarch_dummy_id called\n");
return gdbarch->dummy_id (gdbarch, this_frame);
}
void
set_gdbarch_unwind_dummy_id (struct gdbarch *gdbarch,
gdbarch_unwind_dummy_id_ftype unwind_dummy_id)
set_gdbarch_dummy_id (struct gdbarch *gdbarch,
gdbarch_dummy_id_ftype dummy_id)
{
gdbarch->unwind_dummy_id = unwind_dummy_id;
gdbarch->dummy_id = dummy_id;
}
int

View File

@ -254,13 +254,13 @@ extern void set_gdbarch_register_type (struct gdbarch *gdbarch, gdbarch_register
/* See gdbint.texinfo, and PUSH_DUMMY_CALL. */
extern int gdbarch_unwind_dummy_id_p (struct gdbarch *gdbarch);
extern int gdbarch_dummy_id_p (struct gdbarch *gdbarch);
typedef struct frame_id (gdbarch_unwind_dummy_id_ftype) (struct gdbarch *gdbarch, struct frame_info *info);
extern struct frame_id gdbarch_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *info);
extern void set_gdbarch_unwind_dummy_id (struct gdbarch *gdbarch, gdbarch_unwind_dummy_id_ftype *unwind_dummy_id);
typedef struct frame_id (gdbarch_dummy_id_ftype) (struct gdbarch *gdbarch, struct frame_info *this_frame);
extern struct frame_id gdbarch_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame);
extern void set_gdbarch_dummy_id (struct gdbarch *gdbarch, gdbarch_dummy_id_ftype *dummy_id);
/* Implement UNWIND_DUMMY_ID and PUSH_DUMMY_CALL, then delete
/* Implement DUMMY_ID and PUSH_DUMMY_CALL, then delete
deprecated_fp_regnum. */
extern int gdbarch_deprecated_fp_regnum (struct gdbarch *gdbarch);

View File

@ -434,8 +434,8 @@ m:const char *:register_name:int regnr:regnr::0
M:struct type *:register_type:int reg_nr:reg_nr
# See gdbint.texinfo, and PUSH_DUMMY_CALL.
M:struct frame_id:unwind_dummy_id:struct frame_info *info:info
# Implement UNWIND_DUMMY_ID and PUSH_DUMMY_CALL, then delete
M:struct frame_id:dummy_id:struct frame_info *this_frame:this_frame
# Implement DUMMY_ID and PUSH_DUMMY_CALL, then delete
# deprecated_fp_regnum.
v:int:deprecated_fp_regnum:::-1:-1::0

View File

@ -2803,7 +2803,6 @@ static const struct frame_unwind ia64_libunwind_frame_unwind =
ia64_libunwind_frame_prev_register,
NULL,
NULL,
NULL,
libunwind_frame_dealloc_cache
};

View File

@ -462,7 +462,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
pushed) GDB won't be able to correctly perform back traces.
If a target is having trouble with backtraces, first thing to
do is add FRAME_ALIGN() to the architecture vector. If that
fails, try unwind_dummy_id().
fails, try dummy_id().
If the ABI specifies a "Red Zone" (see the doco) the code
below will quietly trash it. */
@ -656,7 +656,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
ID so that the breakpoint code can correctly re-identify the
dummy breakpoint. */
/* Sanity. The exact same SP value is returned by PUSH_DUMMY_CALL,
saved as the dummy-frame TOS, and used by unwind_dummy_id to form
saved as the dummy-frame TOS, and used by dummy_id to form
the frame ID's stack address. */
dummy_id = frame_id_build (sp, bp_addr);
@ -671,7 +671,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
sal.section = find_pc_overlay (sal.pc);
/* Sanity. The exact same SP value is returned by
PUSH_DUMMY_CALL, saved as the dummy-frame TOS, and used by
unwind_dummy_id to form the frame ID's stack address. */
dummy_id to form the frame ID's stack address. */
bpt = set_momentary_breakpoint (sal, dummy_id, bp_call_dummy);
bpt->disposition = disp_del;
}

View File

@ -214,7 +214,6 @@ static const struct frame_unwind libunwind_frame_unwind =
libunwind_frame_prev_register,
NULL,
NULL,
NULL,
libunwind_frame_dealloc_cache
};

View File

@ -42,34 +42,31 @@ sentinel_frame_cache (struct regcache *regcache)
/* Here the register value is taken direct from the register cache. */
static void
sentinel_frame_prev_register (struct frame_info *next_frame,
static struct value *
sentinel_frame_prev_register (struct frame_info *this_frame,
void **this_prologue_cache,
int regnum, int *optimized,
enum lval_type *lvalp, CORE_ADDR *addrp,
int *realnum, gdb_byte *bufferp)
int regnum)
{
struct gdbarch *gdbarch = get_frame_arch (this_frame);
struct frame_unwind_cache *cache = *this_prologue_cache;
/* Describe the register's location. A reg-frame maps all registers
onto the corresponding hardware register. */
*optimized = 0;
*lvalp = lval_register;
*addrp = 0;
*realnum = regnum;
struct value *value;
/* If needed, find and return the value of the register. */
if (bufferp != NULL)
{
/* Return the actual value. */
/* Use the regcache_cooked_read() method so that it, on the fly,
constructs either a raw or pseudo register from the raw
register cache. */
regcache_cooked_read (cache->regcache, regnum, bufferp);
}
/* Return the actual value. */
value = allocate_value (register_type (gdbarch, regnum));
VALUE_LVAL (value) = lval_register;
VALUE_REGNUM (value) = regnum;
VALUE_FRAME_ID (value) = get_frame_id (this_frame);
/* Use the regcache_cooked_read() method so that it, on the fly,
constructs either a raw or pseudo register from the raw
register cache. */
regcache_cooked_read (cache->regcache, regnum, value_contents_raw (value));
return value;
}
static void
sentinel_frame_this_id (struct frame_info *next_frame,
sentinel_frame_this_id (struct frame_info *this_frame,
void **this_prologue_cache,
struct frame_id *this_id)
{
@ -79,22 +76,11 @@ sentinel_frame_this_id (struct frame_info *next_frame,
internal_error (__FILE__, __LINE__, _("sentinel_frame_this_id called"));
}
static CORE_ADDR
sentinel_frame_prev_pc (struct frame_info *next_frame,
void **this_prologue_cache)
{
struct gdbarch *gdbarch = get_frame_arch (next_frame);
return gdbarch_unwind_pc (gdbarch, next_frame);
}
const struct frame_unwind sentinel_frame_unwinder =
{
SENTINEL_FRAME,
sentinel_frame_this_id,
sentinel_frame_prev_register,
NULL, /* unwind_data */
NULL, /* sniffer */
sentinel_frame_prev_pc,
sentinel_frame_prev_register
};
const struct frame_unwind *const sentinel_frame_unwind = &sentinel_frame_unwinder;

View File

@ -622,24 +622,87 @@ value_fetch_lazy (struct value *val)
}
else if (VALUE_LVAL (val) == lval_register)
{
struct frame_info *frame = frame_find_by_id (VALUE_FRAME_ID (val));
int regnum = VALUE_REGNUM (val);
struct frame_info *frame;
int regnum;
struct type *type = check_typedef (value_type (val));
struct value *new_val = val, *mark = value_mark ();
gdb_assert (frame != NULL);
/* Offsets are not supported here; lazy register values must
refer to the entire register. */
gdb_assert (value_offset (val) == 0);
/* Convertible register routines are used for multi-register
values and for interpretation in different types (e.g. float
or int from a double register). Lazy register values should
have the register's natural type, so they do not apply. */
gdb_assert (!gdbarch_convert_register_p (get_frame_arch (frame), regnum,
type));
while (VALUE_LVAL (new_val) == lval_register && value_lazy (new_val))
{
frame = frame_find_by_id (VALUE_FRAME_ID (new_val));
regnum = VALUE_REGNUM (new_val);
/* Get the data. */
if (!get_frame_register_bytes (frame, regnum, value_offset (val),
TYPE_LENGTH (value_type (val)),
value_contents_raw (val)))
gdb_assert (frame != NULL);
/* Convertible register routines are used for multi-register
values and for interpretation in different types
(e.g. float or int from a double register). Lazy
register values should have the register's natural type,
so they do not apply. */
gdb_assert (!gdbarch_convert_register_p (get_frame_arch (frame),
regnum, type));
new_val = get_frame_register_value (frame, regnum);
}
/* If it's still lazy (for instance, a saved register on the
stack), fetch it. */
if (value_lazy (new_val))
value_fetch_lazy (new_val);
/* If the register was not saved, mark it unavailable. */
if (value_optimized_out (new_val))
set_value_optimized_out (val, 1);
else
memcpy (value_contents_raw (val), value_contents (new_val),
TYPE_LENGTH (type));
if (frame_debug)
{
frame = frame_find_by_id (VALUE_FRAME_ID (val));
regnum = VALUE_REGNUM (val);
fprintf_unfiltered (gdb_stdlog, "\
{ value_fetch_lazy (frame=%d,regnum=%d(%s),...) ",
frame_relative_level (frame), regnum,
frame_map_regnum_to_name (frame, regnum));
fprintf_unfiltered (gdb_stdlog, "->");
if (value_optimized_out (new_val))
fprintf_unfiltered (gdb_stdlog, " optimized out");
else
{
int i;
const gdb_byte *buf = value_contents (new_val);
if (VALUE_LVAL (new_val) == lval_register)
fprintf_unfiltered (gdb_stdlog, " register=%d",
VALUE_REGNUM (new_val));
else if (VALUE_LVAL (new_val) == lval_memory)
fprintf_unfiltered (gdb_stdlog, " address=0x%s",
paddr_nz (VALUE_ADDRESS (new_val)));
else
fprintf_unfiltered (gdb_stdlog, " computed");
fprintf_unfiltered (gdb_stdlog, " bytes=");
fprintf_unfiltered (gdb_stdlog, "[");
for (i = 0;
i < register_size (get_frame_arch (frame), regnum);
i++)
fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]);
fprintf_unfiltered (gdb_stdlog, "]");
}
fprintf_unfiltered (gdb_stdlog, " }\n");
}
/* Dispose of the intermediate values. This prevents
watchpoints from trying to watch the saved frame pointer. */
value_free_to_mark (mark);
}
else
internal_error (__FILE__, __LINE__, "Unexpected lazy value type.");