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:
parent
9214ee5f5f
commit
669fac235d
19 changed files with 687 additions and 321 deletions
|
@ -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
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
208
gdb/frame.c
208
gdb/frame.c
|
@ -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;
|
||||
|
|
18
gdb/frame.h
18
gdb/frame.h
|
@ -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):
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -214,7 +214,6 @@ static const struct frame_unwind libunwind_frame_unwind =
|
|||
libunwind_frame_prev_register,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
libunwind_frame_dealloc_cache
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
89
gdb/valops.c
89
gdb/valops.c
|
@ -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.");
|
||||
|
|
Loading…
Add table
Reference in a new issue