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>
|
2008-04-30 Daniel Jacobowitz <dan@codesourcery.com>
|
||||||
|
|
||||||
* ada-lang.c (ada_value_primitive_packed_val): Only check
|
* 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) \
|
$(annotate_h) $(language_h) $(frame_unwind_h) $(frame_base_h) \
|
||||||
$(command_h) $(gdbcmd_h) $(observer_h) $(objfiles_h) $(exceptions_h)
|
$(command_h) $(gdbcmd_h) $(observer_h) $(objfiles_h) $(exceptions_h)
|
||||||
frame-unwind.o: frame-unwind.c $(defs_h) $(frame_h) $(frame_unwind_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) \
|
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) \
|
$(frame_h) $(osabi_h) $(regcache_h) $(elf_bfd_h) $(elf_frv_h) \
|
||||||
$(frv_tdep_h) $(trad_frame_h) $(frame_unwind_h) $(regset_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>
|
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.
|
output does not necessary include any tokens.
|
||||||
|
|
||||||
2008-04-22 Corinna Vinschen <vinschen@redhat.com>
|
2008-04-22 Corinna Vinschen <vinschen@redhat.com>
|
||||||
|
@ -223,7 +230,7 @@
|
||||||
|
|
||||||
2007-12-17 Luis Machado <luisgpm@br.ibm.com>
|
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>
|
2007-12-16 Daniel Jacobowitz <dan@codesourcery.com>
|
||||||
|
|
||||||
|
@ -715,7 +722,7 @@
|
||||||
|
|
||||||
2007-02-26 Daniel Jacobowitz <dan@codesourcery.com>
|
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.
|
case insensitivity.
|
||||||
(ARM Features): Describe org.gnu.gdb.xscale.iwmmxt.
|
(ARM Features): Describe org.gnu.gdb.xscale.iwmmxt.
|
||||||
|
|
||||||
|
@ -744,7 +751,7 @@
|
||||||
(Target Description Format): Document new elements. Use
|
(Target Description Format): Document new elements. Use
|
||||||
@smallexample.
|
@smallexample.
|
||||||
(Predefined Target Types, Standard Target Features): New sections.
|
(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>
|
2007-02-07 Daniel Jacobowitz <dan@codesourcery.com>
|
||||||
|
|
||||||
|
@ -1017,7 +1024,7 @@
|
||||||
|
|
||||||
2006-07-05 Daniel Jacobowitz <dan@codesourcery.com>
|
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.
|
(GDB/MI Kod Commands): Remove commented out node.
|
||||||
|
|
||||||
2006-07-01 Eli Zaretskii <eliz@gnu.org>
|
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::
|
* Algorithms::
|
||||||
* User Interface::
|
* User Interface::
|
||||||
* libgdb::
|
* libgdb::
|
||||||
|
* Stack Frames::
|
||||||
* Symbol Handling::
|
* Symbol Handling::
|
||||||
* Language Support::
|
* Language Support::
|
||||||
* Host Definition::
|
* 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
|
algorithms and mentions some of the specific target definitions that
|
||||||
they use.
|
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
|
@section Prologue Analysis
|
||||||
|
|
||||||
@cindex 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
|
builder. The result of the query is constructed using that builder
|
||||||
before the query function returns.
|
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
|
@node Symbol Handling
|
||||||
|
|
||||||
@chapter 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}
|
Return the name of register @var{regnr} as a string. May return @code{NULL}
|
||||||
to indicate that @var{regnr} is not a valid register.
|
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})
|
@item int gdbarch_sdb_reg_to_regnum (@var{gdbarch}, @var{sdb_regnr})
|
||||||
@findex gdbarch_sdb_reg_to_regnum
|
@findex gdbarch_sdb_reg_to_regnum
|
||||||
Use this function to convert sdb register @var{sdb_regnr} into @value{GDBN}
|
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
|
@file{include/dis-asm.h} used to pass information to the instruction
|
||||||
decoding routine.
|
decoding routine.
|
||||||
|
|
||||||
@item frame_id gdbarch_unwind_dummy_id (@var{gdbarch}, @var{frame})
|
@item frame_id gdbarch_dummy_id (@var{gdbarch}, @var{frame})
|
||||||
@findex gdbarch_unwind_dummy_id
|
@findex gdbarch_dummy_id
|
||||||
@anchor{gdbarch_unwind_dummy_id} Given @var{frame} return a @w{@code{struct
|
@anchor{gdbarch_dummy_id} Given @var{frame} return a @w{@code{struct
|
||||||
frame_id}} that uniquely identifies an inferior function call's dummy
|
frame_id}} that uniquely identifies an inferior function call's dummy
|
||||||
frame. The value returned must match the dummy frame stack value
|
frame. The value returned must match the dummy frame stack value
|
||||||
previously saved using @code{SAVE_DUMMY_FRAME_TOS}.
|
previously saved by @code{call_function_by_hand}.
|
||||||
@xref{SAVE_DUMMY_FRAME_TOS}.
|
|
||||||
|
|
||||||
@item DEPRECATED_USE_STRUCT_CONVENTION (@var{gcc_p}, @var{type})
|
@item DEPRECATED_USE_STRUCT_CONVENTION (@var{gcc_p}, @var{type})
|
||||||
@findex DEPRECATED_USE_STRUCT_CONVENTION
|
@findex DEPRECATED_USE_STRUCT_CONVENTION
|
||||||
|
|
|
@ -39,7 +39,7 @@ struct dummy_frame
|
||||||
{
|
{
|
||||||
struct dummy_frame *next;
|
struct dummy_frame *next;
|
||||||
/* This frame's ID. Must match the value returned by
|
/* This frame's ID. Must match the value returned by
|
||||||
gdbarch_unwind_dummy_id. */
|
gdbarch_dummy_id. */
|
||||||
struct frame_id id;
|
struct frame_id id;
|
||||||
/* The caller's regcache. */
|
/* The caller's regcache. */
|
||||||
struct regcache *regcache;
|
struct regcache *regcache;
|
||||||
|
@ -124,7 +124,7 @@ struct dummy_frame_cache
|
||||||
|
|
||||||
int
|
int
|
||||||
dummy_frame_sniffer (const struct frame_unwind *self,
|
dummy_frame_sniffer (const struct frame_unwind *self,
|
||||||
struct frame_info *next_frame,
|
struct frame_info *this_frame,
|
||||||
void **this_prologue_cache)
|
void **this_prologue_cache)
|
||||||
{
|
{
|
||||||
struct dummy_frame *dummyframe;
|
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. */
|
/* Don't bother unles there is at least one dummy frame. */
|
||||||
if (dummy_frame_stack != NULL)
|
if (dummy_frame_stack != NULL)
|
||||||
{
|
{
|
||||||
/* Use an architecture specific method to extract the prev's
|
/* Use an architecture specific method to extract this frame's
|
||||||
dummy ID from the next frame. Note that this method uses
|
dummy ID, assuming it is a dummy frame. */
|
||||||
frame_register_unwind to obtain the register values needed to
|
this_id = gdbarch_dummy_id (get_frame_arch (this_frame), this_frame);
|
||||||
determine the dummy frame's ID. */
|
|
||||||
this_id = gdbarch_unwind_dummy_id (get_frame_arch (next_frame),
|
|
||||||
next_frame);
|
|
||||||
|
|
||||||
/* Use that ID to find the corresponding cache entry. */
|
/* Use that ID to find the corresponding cache entry. */
|
||||||
for (dummyframe = dummy_frame_stack;
|
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
|
/* Given a call-dummy dummy-frame, return the registers. Here the
|
||||||
register value is taken from the local copy of the register buffer. */
|
register value is taken from the local copy of the register buffer. */
|
||||||
|
|
||||||
static void
|
static struct value *
|
||||||
dummy_frame_prev_register (struct frame_info *next_frame,
|
dummy_frame_prev_register (struct frame_info *this_frame,
|
||||||
void **this_prologue_cache,
|
void **this_prologue_cache,
|
||||||
int regnum, int *optimized,
|
int regnum)
|
||||||
enum lval_type *lvalp, CORE_ADDR *addrp,
|
|
||||||
int *realnum, gdb_byte *bufferp)
|
|
||||||
{
|
{
|
||||||
/* The dummy-frame sniffer always fills in the cache. */
|
|
||||||
struct dummy_frame_cache *cache = (*this_prologue_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);
|
gdb_assert (cache != NULL);
|
||||||
|
|
||||||
/* Describe the register's location. Generic dummy frames always
|
/* Describe the register's location. Generic dummy frames always
|
||||||
have the register value in an ``expression''. */
|
have the register value in an ``expression''. */
|
||||||
*optimized = 0;
|
reg_val = value_zero (register_type (gdbarch, regnum), not_lval);
|
||||||
*lvalp = not_lval;
|
|
||||||
*addrp = 0;
|
|
||||||
*realnum = -1;
|
|
||||||
|
|
||||||
/* If needed, find and return the value of the register. */
|
/* Use the regcache_cooked_read() method so that it, on the fly,
|
||||||
if (bufferp != NULL)
|
constructs either a raw or pseudo register from the raw
|
||||||
{
|
register cache. */
|
||||||
/* Return the actual value. */
|
regcache_cooked_read (cache->prev_regcache, regnum,
|
||||||
/* Use the regcache_cooked_read() method so that it, on the fly,
|
value_contents_writeable (reg_val));
|
||||||
constructs either a raw or pseudo register from the raw
|
return reg_val;
|
||||||
register cache. */
|
|
||||||
regcache_cooked_read (cache->prev_regcache, regnum, bufferp);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Assuming that THIS frame is a dummy (remember, the NEXT and not
|
/* Assuming that THIS frame is a dummy, return the ID of THIS frame. That ID is
|
||||||
THIS frame is passed in), return the ID of THIS frame. That ID is
|
|
||||||
determined by examining the NEXT frame's unwound registers using
|
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. */
|
dummy cache is located and and saved in THIS_PROLOGUE_CACHE. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dummy_frame_this_id (struct frame_info *next_frame,
|
dummy_frame_this_id (struct frame_info *this_frame,
|
||||||
void **this_prologue_cache,
|
void **this_prologue_cache,
|
||||||
struct frame_id *this_id)
|
struct frame_id *this_id)
|
||||||
{
|
{
|
||||||
|
|
|
@ -28,22 +28,21 @@
|
||||||
really need to override this. */
|
really need to override this. */
|
||||||
|
|
||||||
static CORE_ADDR
|
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! */
|
return get_frame_base (this_frame); /* sigh! */
|
||||||
}
|
}
|
||||||
|
|
||||||
static CORE_ADDR
|
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
|
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 = {
|
const struct frame_base default_frame_base = {
|
||||||
|
@ -97,16 +96,16 @@ frame_base_set_default (struct gdbarch *gdbarch,
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct frame_base *
|
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 *table = gdbarch_data (gdbarch, frame_base_data);
|
||||||
struct frame_base_table_entry *entry;
|
struct frame_base_table_entry *entry;
|
||||||
|
|
||||||
for (entry = table->head; entry != NULL; entry = entry->next)
|
for (entry = table->head; entry != NULL; entry = entry->next)
|
||||||
{
|
{
|
||||||
const struct frame_base *desc = NULL;
|
const struct frame_base *desc = NULL;
|
||||||
desc = entry->sniffer (next_frame);
|
desc = entry->sniffer (this_frame);
|
||||||
if (desc != NULL)
|
if (desc != NULL)
|
||||||
return desc;
|
return desc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,9 +28,9 @@ struct gdbarch;
|
||||||
struct regcache;
|
struct regcache;
|
||||||
|
|
||||||
/* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
|
/* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
|
||||||
and that this is a `normal frame'; use the NEXT frame, and its
|
and that this is a `normal frame'; use THIS frame, and implicitly
|
||||||
register unwind method, to determine the address of THIS frame's
|
the NEXT frame's register unwind method, to determine the address
|
||||||
`base'.
|
of THIS frame's `base'.
|
||||||
|
|
||||||
The exact meaning of `base' is highly dependant on the type of the
|
The exact meaning of `base' is highly dependant on the type of the
|
||||||
debug info. It is assumed that dwarf2, stabs, ... will each
|
debug info. It is assumed that dwarf2, stabs, ... will each
|
||||||
|
@ -42,17 +42,17 @@ struct regcache;
|
||||||
|
|
||||||
/* A generic base address. */
|
/* 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);
|
void **this_base_cache);
|
||||||
|
|
||||||
/* The base address of the frame's local variables. */
|
/* 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);
|
void **this_base_cache);
|
||||||
|
|
||||||
/* The base address of the frame's arguments / parameters. */
|
/* 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);
|
void **this_base_cache);
|
||||||
|
|
||||||
struct frame_base
|
struct frame_base
|
||||||
|
@ -65,10 +65,10 @@ struct frame_base
|
||||||
frame_this_args_ftype *this_args;
|
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. */
|
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
|
/* Append a frame base sniffer to the list. The sniffers are polled
|
||||||
in the order that they are appended. */
|
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
|
/* Iterate through the list of frame base handlers until one returns
|
||||||
an implementation. */
|
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
|
#endif
|
||||||
|
|
|
@ -20,15 +20,17 @@
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
#include "frame.h"
|
#include "frame.h"
|
||||||
#include "frame-unwind.h"
|
#include "frame-unwind.h"
|
||||||
#include "gdb_assert.h"
|
|
||||||
#include "dummy-frame.h"
|
#include "dummy-frame.h"
|
||||||
|
#include "value.h"
|
||||||
|
#include "regcache.h"
|
||||||
|
|
||||||
|
#include "gdb_assert.h"
|
||||||
#include "gdb_obstack.h"
|
#include "gdb_obstack.h"
|
||||||
|
|
||||||
static struct gdbarch_data *frame_unwind_data;
|
static struct gdbarch_data *frame_unwind_data;
|
||||||
|
|
||||||
struct frame_unwind_table_entry
|
struct frame_unwind_table_entry
|
||||||
{
|
{
|
||||||
frame_unwind_sniffer_ftype *sniffer;
|
|
||||||
const struct frame_unwind *unwinder;
|
const struct frame_unwind *unwinder;
|
||||||
struct frame_unwind_table_entry *next;
|
struct frame_unwind_table_entry *next;
|
||||||
};
|
};
|
||||||
|
@ -54,19 +56,6 @@ frame_unwind_init (struct obstack *obstack)
|
||||||
return table;
|
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
|
void
|
||||||
frame_unwind_prepend_unwinder (struct gdbarch *gdbarch,
|
frame_unwind_prepend_unwinder (struct gdbarch *gdbarch,
|
||||||
const struct frame_unwind *unwinder)
|
const struct frame_unwind *unwinder)
|
||||||
|
@ -81,32 +70,123 @@ frame_unwind_prepend_unwinder (struct gdbarch *gdbarch,
|
||||||
(*table->osabi_head) = entry;
|
(*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 *
|
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;
|
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 *table = gdbarch_data (gdbarch, frame_unwind_data);
|
||||||
struct frame_unwind_table_entry *entry;
|
struct frame_unwind_table_entry *entry;
|
||||||
|
struct cleanup *old_cleanup;
|
||||||
for (entry = table->list; entry != NULL; entry = entry->next)
|
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;
|
discard_cleanups (old_cleanup);
|
||||||
desc = entry->sniffer (next_frame);
|
return entry->unwinder;
|
||||||
if (desc != NULL)
|
|
||||||
return desc;
|
|
||||||
}
|
|
||||||
if (entry->unwinder != NULL)
|
|
||||||
{
|
|
||||||
if (entry->unwinder->sniffer (entry->unwinder, next_frame,
|
|
||||||
this_cache))
|
|
||||||
return entry->unwinder;
|
|
||||||
}
|
}
|
||||||
|
do_cleanups (old_cleanup);
|
||||||
}
|
}
|
||||||
internal_error (__FILE__, __LINE__, _("frame_unwind_find_by_frame failed"));
|
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 */
|
extern initialize_file_ftype _initialize_frame_unwind; /* -Wmissing-prototypes */
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -26,6 +26,7 @@ struct frame_id;
|
||||||
struct frame_unwind;
|
struct frame_unwind;
|
||||||
struct gdbarch;
|
struct gdbarch;
|
||||||
struct regcache;
|
struct regcache;
|
||||||
|
struct value;
|
||||||
|
|
||||||
#include "frame.h" /* For enum frame_type. */
|
#include "frame.h" /* For enum frame_type. */
|
||||||
|
|
||||||
|
@ -41,17 +42,24 @@ struct regcache;
|
||||||
as where this frame's prologue stores the previous frame's
|
as where this frame's prologue stores the previous frame's
|
||||||
registers. */
|
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,
|
the PC and attributes) and if SELF is the applicable unwinder,
|
||||||
return non-zero. Possibly also initialize THIS_PROLOGUE_CACHE. */
|
return non-zero. Possibly also initialize THIS_PROLOGUE_CACHE. */
|
||||||
|
|
||||||
typedef int (frame_sniffer_ftype) (const struct frame_unwind *self,
|
typedef int (frame_sniffer_ftype) (const struct frame_unwind *self,
|
||||||
struct frame_info *next_frame,
|
struct frame_info *this_frame,
|
||||||
void **this_prologue_cache);
|
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);
|
/* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
|
||||||
use the NEXT frame, and its register unwind method, to determine
|
use THIS frame, and through it the NEXT frame's register unwind
|
||||||
the frame ID of THIS frame.
|
method, to determine the frame ID of THIS frame.
|
||||||
|
|
||||||
A frame ID provides an invariant that can be used to re-identify an
|
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
|
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
|
with the other unwind methods. Memory for that cache should be
|
||||||
allocated using FRAME_OBSTACK_ZALLOC(). */
|
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,
|
void **this_prologue_cache,
|
||||||
struct frame_id *this_id);
|
struct frame_id *this_id);
|
||||||
|
|
||||||
/* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
|
/* Assuming the frame chain: (outer) prev <-> this <-> next (inner);
|
||||||
use the NEXT frame, and its register unwind method, to unwind THIS
|
use THIS frame, and implicitly the NEXT frame's register unwind
|
||||||
frame's registers (returning the value of the specified register
|
method, to unwind THIS frame's registers (returning the value of
|
||||||
REGNUM in the previous frame).
|
the specified register REGNUM in the previous frame).
|
||||||
|
|
||||||
Traditionally, THIS frame's registers were unwound by examining
|
Traditionally, THIS frame's registers were unwound by examining
|
||||||
THIS frame's function's prologue and identifying which registers
|
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
|
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.
|
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
|
This function takes THIS_FRAME as an argument. It can find the
|
||||||
cache, the supplied parameters are consistent with the sibling
|
values of registers in THIS frame by calling get_frame_register
|
||||||
function THIS_ID.
|
(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))''?
|
The result is a GDB value object describing the register value. It
|
||||||
Won't the call frame_register (THIS_FRAME) be faster? Well,
|
may be a lazy reference to memory, a lazy reference to the value of
|
||||||
ignoring the possability that the previous frame does not yet
|
a register in THIS frame, or a non-lvalue.
|
||||||
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.
|
|
||||||
|
|
||||||
THIS_PROLOGUE_CACHE can be used to share any prolog analysis data
|
THIS_PROLOGUE_CACHE can be used to share any prolog analysis data
|
||||||
with the other unwind methods. Memory for that cache should be
|
with the other unwind methods. Memory for that cache should be
|
||||||
allocated using FRAME_OBSTACK_ZALLOC(). */
|
allocated using FRAME_OBSTACK_ZALLOC(). */
|
||||||
|
|
||||||
typedef void (frame_prev_register_ftype) (struct frame_info *next_frame,
|
typedef struct value * (frame_prev_register_ftype)
|
||||||
void **this_prologue_cache,
|
(struct frame_info *this_frame, void **this_prologue_cache,
|
||||||
int prev_regnum,
|
int 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);
|
|
||||||
|
|
||||||
/* Deallocate extra memory associated with the frame cache if any. */
|
/* Deallocate extra memory associated with the frame cache if any. */
|
||||||
|
|
||||||
|
@ -139,7 +132,6 @@ struct frame_unwind
|
||||||
frame_prev_register_ftype *prev_register;
|
frame_prev_register_ftype *prev_register;
|
||||||
const struct frame_data *unwind_data;
|
const struct frame_data *unwind_data;
|
||||||
frame_sniffer_ftype *sniffer;
|
frame_sniffer_ftype *sniffer;
|
||||||
frame_prev_pc_ftype *prev_pc;
|
|
||||||
frame_dealloc_cache_ftype *dealloc_cache;
|
frame_dealloc_cache_ftype *dealloc_cache;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -152,23 +144,50 @@ struct frame_unwind
|
||||||
extern void frame_unwind_prepend_unwinder (struct gdbarch *gdbarch,
|
extern void frame_unwind_prepend_unwinder (struct gdbarch *gdbarch,
|
||||||
const struct frame_unwind *unwinder);
|
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
|
/* Add a frame sniffer to the list. The predicates are polled in the
|
||||||
order that they are appended. The initial list contains the dummy
|
order that they are appended. The initial list contains the dummy
|
||||||
frame sniffer. */
|
frame sniffer. */
|
||||||
|
|
||||||
extern void frame_unwind_append_sniffer (struct gdbarch *gdbarch,
|
extern void frame_unwind_append_unwinder (struct gdbarch *gdbarch,
|
||||||
frame_unwind_sniffer_ftype *sniffer);
|
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. */
|
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);
|
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
|
#endif
|
||||||
|
|
208
gdb/frame.c
208
gdb/frame.c
|
@ -113,7 +113,7 @@ struct frame_info
|
||||||
|
|
||||||
/* Flag to control debugging. */
|
/* Flag to control debugging. */
|
||||||
|
|
||||||
static int frame_debug;
|
int frame_debug;
|
||||||
static void
|
static void
|
||||||
show_frame_debug (struct ui_file *file, int from_tty,
|
show_frame_debug (struct ui_file *file, int from_tty,
|
||||||
struct cmd_list_element *c, const char *value)
|
struct cmd_list_element *c, const char *value)
|
||||||
|
@ -255,10 +255,9 @@ get_frame_id (struct frame_info *fi)
|
||||||
fi->level);
|
fi->level);
|
||||||
/* Find the unwinder. */
|
/* Find the unwinder. */
|
||||||
if (fi->unwind == NULL)
|
if (fi->unwind == NULL)
|
||||||
fi->unwind = frame_unwind_find_by_frame (fi->next,
|
fi->unwind = frame_unwind_find_by_frame (fi, &fi->prologue_cache);
|
||||||
&fi->prologue_cache);
|
|
||||||
/* Find THIS frame's ID. */
|
/* 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;
|
fi->this_id.p = 1;
|
||||||
if (frame_debug)
|
if (frame_debug)
|
||||||
{
|
{
|
||||||
|
@ -427,15 +426,7 @@ frame_pc_unwind (struct frame_info *this_frame)
|
||||||
if (!this_frame->prev_pc.p)
|
if (!this_frame->prev_pc.p)
|
||||||
{
|
{
|
||||||
CORE_ADDR pc;
|
CORE_ADDR pc;
|
||||||
if (this_frame->unwind == NULL)
|
if (gdbarch_unwind_pc_p (get_frame_arch (this_frame)))
|
||||||
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)))
|
|
||||||
{
|
{
|
||||||
/* The right way. The `pure' way. The one true way. This
|
/* The right way. The `pure' way. The one true way. This
|
||||||
method depends solely on the register-unwind code to
|
method depends solely on the register-unwind code to
|
||||||
|
@ -495,8 +486,7 @@ get_frame_func (struct frame_info *fi)
|
||||||
static int
|
static int
|
||||||
do_frame_register_read (void *src, int regnum, gdb_byte *buf)
|
do_frame_register_read (void *src, int regnum, gdb_byte *buf)
|
||||||
{
|
{
|
||||||
frame_register_read (src, regnum, buf);
|
return frame_register_read (src, regnum, buf);
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct regcache *
|
struct regcache *
|
||||||
|
@ -552,15 +542,7 @@ frame_register_unwind (struct frame_info *frame, int regnum,
|
||||||
int *optimizedp, enum lval_type *lvalp,
|
int *optimizedp, enum lval_type *lvalp,
|
||||||
CORE_ADDR *addrp, int *realnump, gdb_byte *bufferp)
|
CORE_ADDR *addrp, int *realnump, gdb_byte *bufferp)
|
||||||
{
|
{
|
||||||
struct frame_unwind_cache *cache;
|
struct value *value;
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Require all but BUFFERP to be valid. A NULL BUFFERP indicates
|
/* Require all but BUFFERP to be valid. A NULL BUFFERP indicates
|
||||||
that the value proper does not need to be fetched. */
|
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 (realnump != NULL);
|
||||||
/* gdb_assert (bufferp != NULL); */
|
/* gdb_assert (bufferp != NULL); */
|
||||||
|
|
||||||
/* NOTE: cagney/2002-11-27: A program trying to unwind a NULL frame
|
value = frame_unwind_register_value (frame, regnum);
|
||||||
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);
|
|
||||||
|
|
||||||
/* Find the unwinder. */
|
gdb_assert (value != NULL);
|
||||||
if (frame->unwind == NULL)
|
|
||||||
frame->unwind = frame_unwind_find_by_frame (frame->next,
|
|
||||||
&frame->prologue_cache);
|
|
||||||
|
|
||||||
/* Ask this frame to unwind its register. See comment in
|
*optimizedp = value_optimized_out (value);
|
||||||
"frame-unwind.h" for why NEXT frame and this unwind cache are
|
*lvalp = VALUE_LVAL (value);
|
||||||
passed in. */
|
*addrp = VALUE_ADDRESS (value);
|
||||||
frame->unwind->prev_register (frame->next, &frame->prologue_cache, regnum,
|
*realnump = VALUE_REGNUM (value);
|
||||||
optimizedp, lvalp, addrp, realnump, bufferp);
|
|
||||||
|
|
||||||
if (frame_debug)
|
if (bufferp)
|
||||||
{
|
memcpy (bufferp, value_contents_all (value),
|
||||||
fprintf_unfiltered (gdb_stdlog, "->");
|
TYPE_LENGTH (value_type (value)));
|
||||||
fprintf_unfiltered (gdb_stdlog, " *optimizedp=%d", (*optimizedp));
|
|
||||||
fprintf_unfiltered (gdb_stdlog, " *lvalp=%d", (int) (*lvalp));
|
/* Dispose of the new value. This prevents watchpoints from
|
||||||
fprintf_unfiltered (gdb_stdlog, " *addrp=0x%s", paddr_nz ((*addrp)));
|
trying to watch the saved frame pointer. */
|
||||||
fprintf_unfiltered (gdb_stdlog, " *bufferp=");
|
release_value (value);
|
||||||
if (bufferp == NULL)
|
value_free (value);
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -647,6 +609,71 @@ get_frame_register (struct frame_info *frame,
|
||||||
frame_unwind_register (frame->next, regnum, buf);
|
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
|
LONGEST
|
||||||
frame_unwind_register_signed (struct frame_info *frame, int regnum)
|
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
|
/* Select/initialize both the unwind function and the frame's type
|
||||||
based on the PC. */
|
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;
|
fi->this_id.p = 1;
|
||||||
deprecated_update_frame_base_hack (fi, addr);
|
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
|
/* Sneaky: If the low-level unwind and high-level base code share a
|
||||||
common unwinder, let them share the prologue cache. */
|
common unwinder, let them share the prologue cache. */
|
||||||
if (fi->base->unwind == fi->unwind)
|
if (fi->base->unwind == fi->unwind)
|
||||||
return fi->base->this_base (fi->next, &fi->prologue_cache);
|
return fi->base->this_base (fi, &fi->prologue_cache);
|
||||||
return fi->base->this_base (fi->next, &fi->base_cache);
|
return fi->base->this_base (fi, &fi->base_cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
CORE_ADDR
|
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
|
/* Sneaky: If the low-level unwind and high-level base code share a
|
||||||
common unwinder, let them share the prologue cache. */
|
common unwinder, let them share the prologue cache. */
|
||||||
if (fi->base->unwind == fi->unwind)
|
if (fi->base->unwind == fi->unwind)
|
||||||
cache = &fi->prologue_cache;
|
return fi->base->this_locals (fi, &fi->prologue_cache);
|
||||||
else
|
return fi->base->this_locals (fi, &fi->base_cache);
|
||||||
cache = &fi->base_cache;
|
|
||||||
return fi->base->this_locals (fi->next, cache);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CORE_ADDR
|
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
|
/* Sneaky: If the low-level unwind and high-level base code share a
|
||||||
common unwinder, let them share the prologue cache. */
|
common unwinder, let them share the prologue cache. */
|
||||||
if (fi->base->unwind == fi->unwind)
|
if (fi->base->unwind == fi->unwind)
|
||||||
cache = &fi->prologue_cache;
|
return fi->base->this_args (fi, &fi->prologue_cache);
|
||||||
else
|
return fi->base->this_args (fi, &fi->base_cache);
|
||||||
cache = &fi->base_cache;
|
|
||||||
return fi->base->this_args (fi->next, cache);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Level of the selected frame: 0 for innermost, 1 for its caller, ...
|
/* 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)
|
if (frame->unwind == NULL)
|
||||||
/* Initialize the frame's unwinder because that's what
|
/* Initialize the frame's unwinder because that's what
|
||||||
provides the frame's type. */
|
provides the frame's type. */
|
||||||
frame->unwind = frame_unwind_find_by_frame (frame->next,
|
frame->unwind = frame_unwind_find_by_frame (frame, &frame->prologue_cache);
|
||||||
&frame->prologue_cache);
|
|
||||||
return frame->unwind->type;
|
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 */
|
extern initialize_file_ftype _initialize_frame; /* -Wmissing-prototypes */
|
||||||
|
|
||||||
static struct cmd_list_element *set_backtrace_cmdlist;
|
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. */
|
/* For convenience. All fields are zero. */
|
||||||
extern const struct frame_id null_frame_id;
|
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
|
/* Construct a frame ID. The first parameter is the frame's constant
|
||||||
stack address (typically the outer-bound), and the second the
|
stack address (typically the outer-bound), and the second the
|
||||||
frame's constant code address (typically the entry point).
|
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
|
/* Fetch a register from this, or unwind a register from the next
|
||||||
frame. Note that the get_frame methods are wrappers to
|
frame. Note that the get_frame methods are wrappers to
|
||||||
frame->next->unwind. They all [potentially] throw an error if the
|
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,
|
extern void frame_unwind_register (struct frame_info *frame,
|
||||||
int regnum, gdb_byte *buf);
|
int regnum, gdb_byte *buf);
|
||||||
extern void get_frame_register (struct frame_info *frame,
|
extern void get_frame_register (struct frame_info *frame,
|
||||||
int regnum, gdb_byte *buf);
|
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,
|
extern LONGEST frame_unwind_register_signed (struct frame_info *frame,
|
||||||
int regnum);
|
int regnum);
|
||||||
extern LONGEST get_frame_register_signed (struct frame_info *frame,
|
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);
|
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):
|
/* 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_dwarf2_reg_to_regnum_ftype *dwarf2_reg_to_regnum;
|
||||||
gdbarch_register_name_ftype *register_name;
|
gdbarch_register_name_ftype *register_name;
|
||||||
gdbarch_register_type_ftype *register_type;
|
gdbarch_register_type_ftype *register_type;
|
||||||
gdbarch_unwind_dummy_id_ftype *unwind_dummy_id;
|
gdbarch_dummy_id_ftype *dummy_id;
|
||||||
int deprecated_fp_regnum;
|
int deprecated_fp_regnum;
|
||||||
gdbarch_push_dummy_call_ftype *push_dummy_call;
|
gdbarch_push_dummy_call_ftype *push_dummy_call;
|
||||||
int call_dummy_location;
|
int call_dummy_location;
|
||||||
|
@ -284,7 +284,7 @@ struct gdbarch startup_gdbarch =
|
||||||
no_op_reg_to_regnum, /* dwarf2_reg_to_regnum */
|
no_op_reg_to_regnum, /* dwarf2_reg_to_regnum */
|
||||||
0, /* register_name */
|
0, /* register_name */
|
||||||
0, /* register_type */
|
0, /* register_type */
|
||||||
0, /* unwind_dummy_id */
|
0, /* dummy_id */
|
||||||
-1, /* deprecated_fp_regnum */
|
-1, /* deprecated_fp_regnum */
|
||||||
0, /* push_dummy_call */
|
0, /* push_dummy_call */
|
||||||
0, /* call_dummy_location */
|
0, /* call_dummy_location */
|
||||||
|
@ -522,7 +522,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
|
||||||
if (gdbarch->register_name == 0)
|
if (gdbarch->register_name == 0)
|
||||||
fprintf_unfiltered (log, "\n\tregister_name");
|
fprintf_unfiltered (log, "\n\tregister_name");
|
||||||
/* Skip verify of register_type, has predicate */
|
/* 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 deprecated_fp_regnum, invalid_p == 0 */
|
||||||
/* Skip verify of push_dummy_call, has predicate */
|
/* Skip verify of push_dummy_call, has predicate */
|
||||||
/* Skip verify of call_dummy_location, invalid_p == 0 */
|
/* 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,
|
fprintf_unfiltered (file,
|
||||||
"gdbarch_dump: double_format = %s\n",
|
"gdbarch_dump: double_format = %s\n",
|
||||||
pformat (gdbarch->double_format));
|
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,
|
fprintf_unfiltered (file,
|
||||||
"gdbarch_dump: dwarf2_reg_to_regnum = <0x%lx>\n",
|
"gdbarch_dump: dwarf2_reg_to_regnum = <0x%lx>\n",
|
||||||
(long) gdbarch->dwarf2_reg_to_regnum);
|
(long) gdbarch->dwarf2_reg_to_regnum);
|
||||||
|
@ -978,12 +984,6 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
|
||||||
fprintf_unfiltered (file,
|
fprintf_unfiltered (file,
|
||||||
"gdbarch_dump: target_desc = %s\n",
|
"gdbarch_dump: target_desc = %s\n",
|
||||||
paddr_d ((long) gdbarch->target_desc));
|
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,
|
fprintf_unfiltered (file,
|
||||||
"gdbarch_dump: gdbarch_unwind_pc_p() = %d\n",
|
"gdbarch_dump: gdbarch_unwind_pc_p() = %d\n",
|
||||||
gdbarch_unwind_pc_p (gdbarch));
|
gdbarch_unwind_pc_p (gdbarch));
|
||||||
|
@ -1646,27 +1646,27 @@ set_gdbarch_register_type (struct gdbarch *gdbarch,
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
gdbarch_unwind_dummy_id_p (struct gdbarch *gdbarch)
|
gdbarch_dummy_id_p (struct gdbarch *gdbarch)
|
||||||
{
|
{
|
||||||
gdb_assert (gdbarch != NULL);
|
gdb_assert (gdbarch != NULL);
|
||||||
return gdbarch->unwind_dummy_id != NULL;
|
return gdbarch->dummy_id != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct frame_id
|
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 != NULL);
|
||||||
gdb_assert (gdbarch->unwind_dummy_id != NULL);
|
gdb_assert (gdbarch->dummy_id != NULL);
|
||||||
if (gdbarch_debug >= 2)
|
if (gdbarch_debug >= 2)
|
||||||
fprintf_unfiltered (gdb_stdlog, "gdbarch_unwind_dummy_id called\n");
|
fprintf_unfiltered (gdb_stdlog, "gdbarch_dummy_id called\n");
|
||||||
return gdbarch->unwind_dummy_id (gdbarch, info);
|
return gdbarch->dummy_id (gdbarch, this_frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
set_gdbarch_unwind_dummy_id (struct gdbarch *gdbarch,
|
set_gdbarch_dummy_id (struct gdbarch *gdbarch,
|
||||||
gdbarch_unwind_dummy_id_ftype unwind_dummy_id)
|
gdbarch_dummy_id_ftype dummy_id)
|
||||||
{
|
{
|
||||||
gdbarch->unwind_dummy_id = unwind_dummy_id;
|
gdbarch->dummy_id = dummy_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
@ -254,13 +254,13 @@ extern void set_gdbarch_register_type (struct gdbarch *gdbarch, gdbarch_register
|
||||||
|
|
||||||
/* See gdbint.texinfo, and PUSH_DUMMY_CALL. */
|
/* 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);
|
typedef struct frame_id (gdbarch_dummy_id_ftype) (struct gdbarch *gdbarch, struct frame_info *this_frame);
|
||||||
extern struct frame_id gdbarch_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *info);
|
extern struct frame_id gdbarch_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame);
|
||||||
extern void set_gdbarch_unwind_dummy_id (struct gdbarch *gdbarch, gdbarch_unwind_dummy_id_ftype *unwind_dummy_id);
|
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. */
|
deprecated_fp_regnum. */
|
||||||
|
|
||||||
extern int gdbarch_deprecated_fp_regnum (struct gdbarch *gdbarch);
|
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
|
M:struct type *:register_type:int reg_nr:reg_nr
|
||||||
|
|
||||||
# See gdbint.texinfo, and PUSH_DUMMY_CALL.
|
# See gdbint.texinfo, and PUSH_DUMMY_CALL.
|
||||||
M:struct frame_id:unwind_dummy_id:struct frame_info *info:info
|
M:struct frame_id:dummy_id:struct frame_info *this_frame:this_frame
|
||||||
# Implement UNWIND_DUMMY_ID and PUSH_DUMMY_CALL, then delete
|
# Implement DUMMY_ID and PUSH_DUMMY_CALL, then delete
|
||||||
# deprecated_fp_regnum.
|
# deprecated_fp_regnum.
|
||||||
v:int:deprecated_fp_regnum:::-1:-1::0
|
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,
|
ia64_libunwind_frame_prev_register,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
|
||||||
libunwind_frame_dealloc_cache
|
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.
|
pushed) GDB won't be able to correctly perform back traces.
|
||||||
If a target is having trouble with backtraces, first thing to
|
If a target is having trouble with backtraces, first thing to
|
||||||
do is add FRAME_ALIGN() to the architecture vector. If that
|
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
|
If the ABI specifies a "Red Zone" (see the doco) the code
|
||||||
below will quietly trash it. */
|
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
|
ID so that the breakpoint code can correctly re-identify the
|
||||||
dummy breakpoint. */
|
dummy breakpoint. */
|
||||||
/* Sanity. The exact same SP value is returned by PUSH_DUMMY_CALL,
|
/* 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. */
|
the frame ID's stack address. */
|
||||||
dummy_id = frame_id_build (sp, bp_addr);
|
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);
|
sal.section = find_pc_overlay (sal.pc);
|
||||||
/* Sanity. The exact same SP value is returned by
|
/* Sanity. The exact same SP value is returned by
|
||||||
PUSH_DUMMY_CALL, saved as the dummy-frame TOS, and used 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 = set_momentary_breakpoint (sal, dummy_id, bp_call_dummy);
|
||||||
bpt->disposition = disp_del;
|
bpt->disposition = disp_del;
|
||||||
}
|
}
|
||||||
|
|
|
@ -214,7 +214,6 @@ static const struct frame_unwind libunwind_frame_unwind =
|
||||||
libunwind_frame_prev_register,
|
libunwind_frame_prev_register,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
|
||||||
libunwind_frame_dealloc_cache
|
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. */
|
/* Here the register value is taken direct from the register cache. */
|
||||||
|
|
||||||
static void
|
static struct value *
|
||||||
sentinel_frame_prev_register (struct frame_info *next_frame,
|
sentinel_frame_prev_register (struct frame_info *this_frame,
|
||||||
void **this_prologue_cache,
|
void **this_prologue_cache,
|
||||||
int regnum, int *optimized,
|
int regnum)
|
||||||
enum lval_type *lvalp, CORE_ADDR *addrp,
|
|
||||||
int *realnum, gdb_byte *bufferp)
|
|
||||||
{
|
{
|
||||||
|
struct gdbarch *gdbarch = get_frame_arch (this_frame);
|
||||||
struct frame_unwind_cache *cache = *this_prologue_cache;
|
struct frame_unwind_cache *cache = *this_prologue_cache;
|
||||||
/* Describe the register's location. A reg-frame maps all registers
|
struct value *value;
|
||||||
onto the corresponding hardware register. */
|
|
||||||
*optimized = 0;
|
|
||||||
*lvalp = lval_register;
|
|
||||||
*addrp = 0;
|
|
||||||
*realnum = regnum;
|
|
||||||
|
|
||||||
/* If needed, find and return the value of the register. */
|
/* Return the actual value. */
|
||||||
if (bufferp != NULL)
|
value = allocate_value (register_type (gdbarch, regnum));
|
||||||
{
|
VALUE_LVAL (value) = lval_register;
|
||||||
/* Return the actual value. */
|
VALUE_REGNUM (value) = regnum;
|
||||||
/* Use the regcache_cooked_read() method so that it, on the fly,
|
VALUE_FRAME_ID (value) = get_frame_id (this_frame);
|
||||||
constructs either a raw or pseudo register from the raw
|
|
||||||
register cache. */
|
/* Use the regcache_cooked_read() method so that it, on the fly,
|
||||||
regcache_cooked_read (cache->regcache, regnum, bufferp);
|
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
|
static void
|
||||||
sentinel_frame_this_id (struct frame_info *next_frame,
|
sentinel_frame_this_id (struct frame_info *this_frame,
|
||||||
void **this_prologue_cache,
|
void **this_prologue_cache,
|
||||||
struct frame_id *this_id)
|
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"));
|
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 =
|
const struct frame_unwind sentinel_frame_unwinder =
|
||||||
{
|
{
|
||||||
SENTINEL_FRAME,
|
SENTINEL_FRAME,
|
||||||
sentinel_frame_this_id,
|
sentinel_frame_this_id,
|
||||||
sentinel_frame_prev_register,
|
sentinel_frame_prev_register
|
||||||
NULL, /* unwind_data */
|
|
||||||
NULL, /* sniffer */
|
|
||||||
sentinel_frame_prev_pc,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct frame_unwind *const sentinel_frame_unwind = &sentinel_frame_unwinder;
|
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)
|
else if (VALUE_LVAL (val) == lval_register)
|
||||||
{
|
{
|
||||||
struct frame_info *frame = frame_find_by_id (VALUE_FRAME_ID (val));
|
struct frame_info *frame;
|
||||||
int regnum = VALUE_REGNUM (val);
|
int regnum;
|
||||||
struct type *type = check_typedef (value_type (val));
|
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
|
while (VALUE_LVAL (new_val) == lval_register && value_lazy (new_val))
|
||||||
values and for interpretation in different types (e.g. float
|
{
|
||||||
or int from a double register). Lazy register values should
|
frame = frame_find_by_id (VALUE_FRAME_ID (new_val));
|
||||||
have the register's natural type, so they do not apply. */
|
regnum = VALUE_REGNUM (new_val);
|
||||||
gdb_assert (!gdbarch_convert_register_p (get_frame_arch (frame), regnum,
|
|
||||||
type));
|
|
||||||
|
|
||||||
/* Get the data. */
|
gdb_assert (frame != NULL);
|
||||||
if (!get_frame_register_bytes (frame, regnum, value_offset (val),
|
|
||||||
TYPE_LENGTH (value_type (val)),
|
/* Convertible register routines are used for multi-register
|
||||||
value_contents_raw (val)))
|
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);
|
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
|
else
|
||||||
internal_error (__FILE__, __LINE__, "Unexpected lazy value type.");
|
internal_error (__FILE__, __LINE__, "Unexpected lazy value type.");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue