summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Jacobowitz <drow@false.org>2008-04-30 21:16:46 +0000
committerDaniel Jacobowitz <drow@false.org>2008-04-30 21:16:46 +0000
commit669fac235d5edab8e2f33c4f3382f3b61671dc8e (patch)
tree2f62ab9d692fd820796a2d9ea9081d0e4ec62434
parent9214ee5f5f55de5082571ea066ea6060497fa229 (diff)
downloadbinutils-gdb-669fac235d5edab8e2f33c4f3382f3b61671dc8e.tar.gz
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.
-rw-r--r--gdb/ChangeLog60
-rw-r--r--gdb/Makefile.in3
-rw-r--r--gdb/doc/ChangeLog17
-rw-r--r--gdb/doc/gdbint.texinfo172
-rw-r--r--gdb/dummy-frame.c55
-rw-r--r--gdb/frame-base.c17
-rw-r--r--gdb/frame-base.h18
-rw-r--r--gdb/frame-unwind.c136
-rw-r--r--gdb/frame-unwind.h107
-rw-r--r--gdb/frame.c208
-rw-r--r--gdb/frame.h18
-rw-r--r--gdb/gdbarch.c36
-rw-r--r--gdb/gdbarch.h10
-rwxr-xr-xgdb/gdbarch.sh4
-rw-r--r--gdb/ia64-tdep.c1
-rw-r--r--gdb/infcall.c6
-rw-r--r--gdb/libunwind-frame.c1
-rw-r--r--gdb/sentinel-frame.c54
-rw-r--r--gdb/valops.c89
19 files changed, 689 insertions, 323 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 7dbdef07e5f..ec0e06c3e1c 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,65 @@
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
value_lazy for memory lvals.
* findvar.c (value_of_register_lazy): New function.
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 9304bc2f586..98ae55892f2 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -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) \
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 9cdf5d98099..2285c835ce7 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -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>
diff --git a/gdb/doc/gdbint.texinfo b/gdb/doc/gdbint.texinfo
index d578347b967..39cb031c38f 100644
--- a/gdb/doc/gdbint.texinfo
+++ b/gdb/doc/gdbint.texinfo
@@ -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
diff --git a/gdb/dummy-frame.c b/gdb/dummy-frame.c
index 3095f76bf89..4c044ef3df4 100644
--- a/gdb/dummy-frame.c
+++ b/gdb/dummy-frame.c
@@ -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;
-
- /* 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);
- }
+ reg_val = value_zero (register_type (gdbarch, regnum), not_lval);
+
+ /* 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)
{
diff --git a/gdb/frame-base.c b/gdb/frame-base.c
index b85d2de385d..e7b6cdd0c40 100644
--- a/gdb/frame-base.c
+++ b/gdb/frame-base.c
@@ -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;
}
diff --git a/gdb/frame-base.h b/gdb/frame-base.h
index 8fbcb28df03..7f10e1e1650 100644
--- a/gdb/frame-base.h
+++ b/gdb/frame-base.h
@@ -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
diff --git a/gdb/frame-unwind.c b/gdb/frame-unwind.c
index 3a2cb7a1f73..73842594334 100644
--- a/gdb/frame-unwind.c
+++ b/gdb/frame-unwind.c
@@ -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;
};
@@ -55,19 +57,6 @@ frame_unwind_init (struct obstack *obstack)
}
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)
- {
- const struct frame_unwind *desc = NULL;
- desc = entry->sniffer (next_frame);
- if (desc != NULL)
- return desc;
- }
- if (entry->unwinder != 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))
{
- 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
diff --git a/gdb/frame-unwind.h b/gdb/frame-unwind.h
index 8140a801300..9ffafffb26f 100644
--- a/gdb/frame-unwind.h
+++ b/gdb/frame-unwind.h
@@ -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
diff --git a/gdb/frame.c b/gdb/frame.c
index 9434ce79d67..f59cbebac77 100644
--- a/gdb/frame.c
+++ b/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;
diff --git a/gdb/frame.h b/gdb/frame.h
index 6d935965be6..c1f9d7eea7b 100644
--- a/gdb/frame.h
+++ b/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):
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index f63dcdc6080..79844232868 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -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 */
@@ -715,6 +715,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *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);
fprintf_unfiltered (file,
@@ -979,12 +985,6 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *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));
fprintf_unfiltered (file,
@@ -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
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 220c2dda7c0..e568993dc86 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -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);
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index 91d970e95c7..e3efdc80b43 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -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
diff --git a/gdb/ia64-tdep.c b/gdb/ia64-tdep.c
index dd2064c9ba9..ebde4dc3723 100644
--- a/gdb/ia64-tdep.c
+++ b/gdb/ia64-tdep.c
@@ -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
};
diff --git a/gdb/infcall.c b/gdb/infcall.c
index ca4785e2e9e..c065b59b42d 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -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;
}
diff --git a/gdb/libunwind-frame.c b/gdb/libunwind-frame.c
index c70c5516ac8..223c3c052de 100644
--- a/gdb/libunwind-frame.c
+++ b/gdb/libunwind-frame.c
@@ -214,7 +214,6 @@ static const struct frame_unwind libunwind_frame_unwind =
libunwind_frame_prev_register,
NULL,
NULL,
- NULL,
libunwind_frame_dealloc_cache
};
diff --git a/gdb/sentinel-frame.c b/gdb/sentinel-frame.c
index ccf03591423..4ad3a4b07bd 100644
--- a/gdb/sentinel-frame.c
+++ b/gdb/sentinel-frame.c
@@ -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;
-
- /* 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);
- }
+ struct value *value;
+
+ /* 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;
diff --git a/gdb/valops.c b/gdb/valops.c
index 7f9868cd391..d601974fba9 100644
--- a/gdb/valops.c
+++ b/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);
+
+ 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);
+ }
- /* Get the data. */
- if (!get_frame_register_bytes (frame, regnum, value_offset (val),
- TYPE_LENGTH (value_type (val)),
- value_contents_raw (val)))
+ /* 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.");