* [RFC 2/5] Frame unwinding using struct value
@ 2008-03-31 22:12 Daniel Jacobowitz
2008-04-01 13:23 ` Eli Zaretskii
` (4 more replies)
0 siblings, 5 replies; 10+ messages in thread
From: Daniel Jacobowitz @ 2008-03-31 22:12 UTC (permalink / raw)
To: gdb-patches
Ref:
http://sourceware.org/ml/gdb/2008-03/msg00282.html
The meat of the conversion. This patch converts frame.c, all the
related frame-unwind and frame-base code, and the dummy and sentinel
unwinders. It also includes helpers for writing new prev_register
methods and a gdbint chapter.
prev_register methods written with the new interface are nicely more
compact. And simpler, because there's less off-by-one juggling
involved. This kills nearly all places we use the next frame that
aren't strictly necessary.
--
Daniel Jacobowitz
CodeSourcery
2008-03-31 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-03-31 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.
---
gdb/Makefile.in | 3
gdb/doc/gdbint.texinfo | 156 +++++++++++++++++++++++++-----------
gdb/dummy-frame.c | 53 +++++-------
gdb/frame-base.c | 17 +--
gdb/frame-base.h | 18 ++--
gdb/frame-unwind.c | 136 +++++++++++++++++++++++++------
gdb/frame-unwind.h | 109 ++++++++++++++-----------
gdb/frame.c | 210 ++++++++++++++++++++++++++++++++-----------------
gdb/frame.h | 18 +++-
gdb/gdbarch.c | 36 ++++----
gdb/gdbarch.h | 10 +-
gdb/gdbarch.sh | 4
gdb/ia64-tdep.c | 1
gdb/infcall.c | 6 -
gdb/libunwind-frame.c | 1
gdb/sentinel-frame.c | 54 ++++--------
gdb/valops.c | 92 ++++++++++++++++++---
17 files changed, 604 insertions(+), 320 deletions(-)
Index: src/gdb/frame.c
===================================================================
--- src.orig/gdb/frame.c 2008-03-31 13:34:20.000000000 -0400
+++ src/gdb/frame.c 2008-03-31 13:39:07.000000000 -0400
@@ -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
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
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
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);
-
- /* Find the unwinder. */
- if (frame->unwind == NULL)
- frame->unwind = frame_unwind_find_by_frame (frame->next,
- &frame->prologue_cache);
+ value = frame_unwind_register_value (frame, regnum);
- /* 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);
+ gdb_assert (value != NULL);
- 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");
- }
+ *optimizedp = value_optimized_out (value);
+ *lvalp = VALUE_LVAL (value);
+ *addrp = VALUE_ADDRESS (value);
+ *realnump = VALUE_REGNUM (value);
+
+ 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 *f
frame_unwind_register (frame->next, regnum, buf);
}
+struct value *
+frame_unwind_register_value (struct frame_info *frame, int regnum)
+{
+ struct value *value;
+
+ 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));
+ }
+
+ gdb_assert (frame != NULL);
+
+ /* 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_A
/* 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_inf
/* 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_i
/* 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_inf
/* 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_st
}
}
+/* 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;
Index: src/gdb/frame.h
===================================================================
--- src.orig/gdb/frame.h 2008-03-31 13:34:20.000000000 -0400
+++ src/gdb/frame.h 2008-03-31 13:39:07.000000000 -0400
@@ -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 (struc
/* 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_
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):
Index: src/gdb/frame-unwind.h
===================================================================
--- src.orig/gdb/frame-unwind.h 2008-03-31 13:34:20.000000000 -0400
+++ src/gdb/frame-unwind.h 2008-03-31 14:43:29.000000000 -0400
@@ -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
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) (stru
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.
-
- 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.
+ 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).
+
+ 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
Index: src/gdb/frame-base.h
===================================================================
--- src.orig/gdb/frame-base.h 2008-03-31 13:34:20.000000000 -0400
+++ src/gdb/frame-base.h 2008-03-31 15:23:52.000000000 -0400
@@ -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 (stru
/* 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
Index: src/gdb/valops.c
===================================================================
--- src.orig/gdb/valops.c 2008-03-31 13:34:22.000000000 -0400
+++ src/gdb/valops.c 2008-03-31 13:39:07.000000000 -0400
@@ -582,24 +582,88 @@ 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));
-
- /* Get the data. */
- if (!get_frame_register_bytes (frame, regnum, value_offset (val),
- TYPE_LENGTH (value_type (val)),
- value_contents_raw (val)))
+ 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);
+ }
+
+ /* 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.");
Index: src/gdb/sentinel-frame.c
===================================================================
--- src.orig/gdb/sentinel-frame.c 2008-03-31 13:34:20.000000000 -0400
+++ src/gdb/sentinel-frame.c 2008-03-31 13:39:07.000000000 -0400
@@ -42,34 +42,31 @@ sentinel_frame_cache (struct regcache *r
/* 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_inf
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;
Index: src/gdb/ia64-tdep.c
===================================================================
--- src.orig/gdb/ia64-tdep.c 2008-03-31 13:34:20.000000000 -0400
+++ src/gdb/ia64-tdep.c 2008-03-31 13:39:07.000000000 -0400
@@ -2796,7 +2796,6 @@ static const struct frame_unwind ia64_li
ia64_libunwind_frame_prev_register,
NULL,
NULL,
- NULL,
libunwind_frame_dealloc_cache
};
Index: src/gdb/libunwind-frame.c
===================================================================
--- src.orig/gdb/libunwind-frame.c 2008-03-31 13:34:20.000000000 -0400
+++ src/gdb/libunwind-frame.c 2008-03-31 13:39:07.000000000 -0400
@@ -214,7 +214,6 @@ static const struct frame_unwind libunwi
libunwind_frame_prev_register,
NULL,
NULL,
- NULL,
libunwind_frame_dealloc_cache
};
Index: src/gdb/frame-unwind.c
===================================================================
--- src.orig/gdb/frame-unwind.c 2008-03-31 13:34:20.000000000 -0400
+++ src/gdb/frame-unwind.c 2008-03-31 14:45:50.000000000 -0400
@@ -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 *obsta
}
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 gd
(*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
Index: src/gdb/dummy-frame.c
===================================================================
--- src.orig/gdb/dummy-frame.c 2008-03-31 13:34:20.000000000 -0400
+++ src/gdb/dummy-frame.c 2008-03-31 13:49:41.000000000 -0400
@@ -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_
/* 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 the 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_
/* Given a call-dummy dummy-frame, return the registers. Here the
register value is taken from the local copy of the register buffer. */
-static void
-dummy_frame_prev_register (struct frame_info *next_frame,
+static struct value *
+dummy_frame_prev_register (struct frame_info *this_frame,
void **this_prologue_cache,
- int regnum, int *optimized,
- enum lval_type *lvalp, CORE_ADDR *addrp,
- int *realnum, gdb_byte *bufferp)
+ int regnum)
{
- /* The dummy-frame sniffer always fills in the cache. */
struct dummy_frame_cache *cache = (*this_prologue_cache);
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ struct value *reg_val;
+
+ /* The dummy-frame sniffer always fills in the cache. */
gdb_assert (cache != NULL);
/* Describe the register's location. Generic dummy frames always
have the register value in an ``expression''. */
- *optimized = 0;
- *lvalp = not_lval;
- *addrp = 0;
- *realnum = -1;
+ reg_val = value_zero (register_type (gdbarch, regnum), not_lval);
- /* If needed, find and return the value of the register. */
- if (bufferp != NULL)
- {
- /* Return the actual value. */
- /* Use the regcache_cooked_read() method so that it, on the fly,
- constructs either a raw or pseudo register from the raw
- register cache. */
- regcache_cooked_read (cache->prev_regcache, regnum, bufferp);
- }
+ /* Use the regcache_cooked_read() method so that it, on the fly,
+ constructs either a raw or pseudo register from the raw
+ register cache. */
+ regcache_cooked_read (cache->prev_regcache, regnum,
+ value_contents_writeable (reg_val));
+ return reg_val;
}
-/* Assuming that THIS frame is a dummy (remember, the NEXT and not
- THIS frame is passed in), return the ID of THIS frame. That ID is
+/* Assuming that THIS frame is a dummy, return the ID of THIS frame. That ID is
determined by examining the NEXT frame's unwound registers using
- the method unwind_dummy_id(). As a side effect, THIS dummy frame's
+ the method dummy_id(). As a side effect, THIS dummy frame's
dummy cache is located and and saved in THIS_PROLOGUE_CACHE. */
static void
-dummy_frame_this_id (struct frame_info *next_frame,
+dummy_frame_this_id (struct frame_info *this_frame,
void **this_prologue_cache,
struct frame_id *this_id)
{
Index: src/gdb/gdbarch.c
===================================================================
--- src.orig/gdb/gdbarch.c 2008-03-31 13:34:20.000000000 -0400
+++ src/gdb/gdbarch.c 2008-03-31 13:39:07.000000000 -0400
@@ -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, s
"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, s
"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 gdbarc
}
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
Index: src/gdb/gdbarch.h
===================================================================
--- src.orig/gdb/gdbarch.h 2008-03-31 13:34:20.000000000 -0400
+++ src/gdb/gdbarch.h 2008-03-31 13:39:07.000000000 -0400
@@ -254,13 +254,13 @@ extern void set_gdbarch_register_type (s
/* 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);
Index: src/gdb/gdbarch.sh
===================================================================
--- src.orig/gdb/gdbarch.sh 2008-03-31 13:34:20.000000000 -0400
+++ src/gdb/gdbarch.sh 2008-03-31 13:39:07.000000000 -0400
@@ -434,8 +434,8 @@ m:const char *:register_name:int regnr:r
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
Index: src/gdb/frame-base.c
===================================================================
--- src.orig/gdb/frame-base.c 2008-03-31 13:34:20.000000000 -0400
+++ src/gdb/frame-base.c 2008-03-31 13:39:07.000000000 -0400
@@ -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 *
}
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;
}
Index: src/gdb/doc/gdbint.texinfo
===================================================================
--- src.orig/gdb/doc/gdbint.texinfo 2008-03-31 13:45:54.000000000 -0400
+++ src/gdb/doc/gdbint.texinfo 2008-03-31 15:15:37.000000000 -0400
@@ -76,6 +76,7 @@ as the mechanisms that adapt @value{GDBN
* Algorithms::
* User Interface::
* libgdb::
+* Stack Frames::
* Symbol Handling::
* Language Support::
* Host Definition::
@@ -273,39 +274,6 @@ cases and real-world issues. This chapt
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,111 @@ the query interface. Each function is p
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 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 Selecting an 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
+
+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.
+
+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 lval type. In most circumstances one of these routines
+will generate the appropriate value:
+
+@table @code
+@item frame_unwind_got_optimized
+This register was not saved.
+
+@item 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
+This register was saved in memory.
+
+@item 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
+Same as @code{frame_unwind_got_constant}, excep 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
@@ -3920,14 +3993,6 @@ This method replaces @w{@code{gdbarch_ca
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}
@@ -4109,13 +4174,12 @@ the @code{opcodes} library (@pxref{Suppo
@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
Index: src/gdb/infcall.c
===================================================================
--- src.orig/gdb/infcall.c 2008-03-31 13:47:54.000000000 -0400
+++ src/gdb/infcall.c 2008-03-31 13:48:20.000000000 -0400
@@ -462,7 +462,7 @@ call_function_by_hand (struct value *fun
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 *fun
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 *fun
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;
}
Index: src/gdb/Makefile.in
===================================================================
--- src.orig/gdb/Makefile.in 2008-03-31 14:36:27.000000000 -0400
+++ src/gdb/Makefile.in 2008-03-31 15:16:00.000000000 -0400
@@ -2119,7 +2119,8 @@ frame.o: frame.c $(defs_h) $(frame_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) \
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [RFC 2/5] Frame unwinding using struct value 2008-03-31 22:12 [RFC 2/5] Frame unwinding using struct value Daniel Jacobowitz @ 2008-04-01 13:23 ` Eli Zaretskii 2008-04-17 15:30 ` Daniel Jacobowitz 2008-04-04 19:10 ` Joel Brobecker ` (3 subsequent siblings) 4 siblings, 1 reply; 10+ messages in thread From: Eli Zaretskii @ 2008-04-01 13:23 UTC (permalink / raw) To: Daniel Jacobowitz; +Cc: gdb-patches > Date: Mon, 31 Mar 2008 18:10:24 -0400 > From: Daniel Jacobowitz <drow@false.org> > > 2008-03-31 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. Thanks, this part is approved, but I have some comments: > +@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 frame, unwind It is not useful to have several index entries that begin with the same string and point to the same page. So I suggest to replace the last one with "@cindex unwind frame". > +Developers wishing to learn more about unwinders, are encouraged to > +read the @sc{dwarf} specification. How about a pointer to the DWARF Spec here? > +is a sentinel frame, then @code{get_frame_type (@var{f}) == > +SENTINEL_FRAME}. I would use @equiv{} here, of even @expansion{}, instead of a literal "==". > +@section Selecting an Unwinder Is it a good idea to have a section without a node? > +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 Please add an @findex entry for each function you mention. > +The returned value must have the same type as the register. It may > +have any lval type. I think we should say "lvalue" here, not "lval". > +Same as @code{frame_unwind_got_constant}, excep that the value is a target ^^^^^ A typo. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC 2/5] Frame unwinding using struct value 2008-04-01 13:23 ` Eli Zaretskii @ 2008-04-17 15:30 ` Daniel Jacobowitz 0 siblings, 0 replies; 10+ messages in thread From: Daniel Jacobowitz @ 2008-04-17 15:30 UTC (permalink / raw) To: gdb-patches As usual, thank you for the comments. On Tue, Apr 01, 2008 at 06:27:58AM +0300, Eli Zaretskii wrote: > Thanks, this part is approved, but I have some comments: > > > +@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 frame, unwind > > It is not useful to have several index entries that begin with the > same string and point to the same page. So I suggest to replace the > last one with "@cindex unwind frame". Sure; I was just moving these, but let's take the opportunity to improve it further. > > +Developers wishing to learn more about unwinders, are encouraged to > > +read the @sc{dwarf} specification. > > How about a pointer to the DWARF Spec here? Sounds good. I expect it will stay on dwarfstd.org for a while; it's had several homes in the last few years. > > +is a sentinel frame, then @code{get_frame_type (@var{f}) == > > +SENTINEL_FRAME}. > > I would use @equiv{} here, of even @expansion{}, instead of a literal > "==". Interesting, I didn't know about those. I like the block of C code -- if you want to check whether something is a sentinel frame in GDB, you type get_frame_type (f) == SENTINEL_FRAME -- but @equiv will do nicely too so I'll use that. > > +@section Selecting an Unwinder > > Is it a good idea to have a section without a node? That's how most of the gdbint manual is currently arranged - one node per chapter, except for a few more substantial ones. I can move the new sections into nodes if you think that's better. > Please add an @findex entry for each function you mention. Done. > I think we should say "lvalue" here, not "lval". Fixed. > > +Same as @code{frame_unwind_got_constant}, excep that the value is a target > ^^^^^ > A typo. Also fixed. I'll repost the final patch in a little while. -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC 2/5] Frame unwinding using struct value 2008-03-31 22:12 [RFC 2/5] Frame unwinding using struct value Daniel Jacobowitz 2008-04-01 13:23 ` Eli Zaretskii @ 2008-04-04 19:10 ` Joel Brobecker 2008-04-17 15:59 ` Daniel Jacobowitz 2008-04-04 19:16 ` Joel Brobecker ` (2 subsequent siblings) 4 siblings, 1 reply; 10+ messages in thread From: Joel Brobecker @ 2008-04-04 19:10 UTC (permalink / raw) To: gdb-patches > +struct value * > +frame_unwind_register_value (struct frame_info *frame, int regnum) > +{ > + struct value *value; > + > + 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)); > + } > + > + gdb_assert (frame != NULL); The gdb_assert should be moved up before the "if (frame_debug)" block. Otherwise, we'll bomb while dereferencing FRAME before we trip the assertion. (I realize that this code was already like this before) Other than that, I tried to read it as carefully as possible and grasp as much of the big picture as I could, and it looked good to me. I can help with the conversion of some of the targets: hppa, ia64, mips (but it would be better if someone having access to mips-linux did it for me, mips-irix results are not stellar right now), powerpc, and sparc. I can't test alpha anymore, for some reason dejagnu no longer works on our Tru64 machines :-(. -- Joel ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC 2/5] Frame unwinding using struct value 2008-04-04 19:10 ` Joel Brobecker @ 2008-04-17 15:59 ` Daniel Jacobowitz 0 siblings, 0 replies; 10+ messages in thread From: Daniel Jacobowitz @ 2008-04-17 15:59 UTC (permalink / raw) To: gdb-patches On Fri, Apr 04, 2008 at 10:22:14AM -0700, Joel Brobecker wrote: > The gdb_assert should be moved up before the "if (frame_debug)" block. > Otherwise, we'll bomb while dereferencing FRAME before we trip the > assertion. (I realize that this code was already like this before) Thanks, fixed. -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC 2/5] Frame unwinding using struct value 2008-03-31 22:12 [RFC 2/5] Frame unwinding using struct value Daniel Jacobowitz 2008-04-01 13:23 ` Eli Zaretskii 2008-04-04 19:10 ` Joel Brobecker @ 2008-04-04 19:16 ` Joel Brobecker 2008-04-07 19:34 ` Thiago Jung Bauermann 2008-04-30 23:31 ` Daniel Jacobowitz 4 siblings, 0 replies; 10+ messages in thread From: Joel Brobecker @ 2008-04-04 19:16 UTC (permalink / raw) To: gdb-patches > (frame_register_unwind): Remove debug messages. Use > frame_unwind_register_value. It looks like we'll also be able to get rid of this function at some point soon. As far as I can tell, I can only find 2 places where it's being used: - mep-tdep.c: But this will disappear as soon as we convert the function using it; - stack.c:frame_info() I think we can adjust the code to use frame_unwind_register_value instead. The code looks like this: /* Find out the location of the saved stack pointer with out actually evaluating it. */ frame_register_unwind (fi, gdbarch_sp_regnum (gdbarch), &optimized, &lval, &addr, &realnum, NULL); if (!optimized && lval == not_lval) { gdb_byte value[MAX_REGISTER_SIZE]; CORE_ADDR sp; frame_register_unwind (fi, gdbarch_sp_regnum (gdbarch), &optimized, &lval, &addr, &realnum, value); /* NOTE: cagney/2003-05-22: This is assuming that the stack pointer was packed as an unsigned integer. That may or may not be valid. */ sp = extract_unsigned_integer (value, register_size (gdbarch, gdbarch_sp_regnum (gdbarch))); printf_filtered (" Previous frame's sp is "); fputs_filtered (paddress (sp), gdb_stdout); printf_filtered ("\n"); need_nl = 0; } else if (!optimized && lval == lval_memory) { printf_filtered (" Previous frame's sp at "); fputs_filtered (paddress (addr), gdb_stdout); printf_filtered ("\n"); need_nl = 0; } else if (!optimized && lval == lval_register) { printf_filtered (" Previous frame's sp in %s\n", gdbarch_register_name (gdbarch, realnum)); need_nl = 0; -- Joel ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC 2/5] Frame unwinding using struct value 2008-03-31 22:12 [RFC 2/5] Frame unwinding using struct value Daniel Jacobowitz ` (2 preceding siblings ...) 2008-04-04 19:16 ` Joel Brobecker @ 2008-04-07 19:34 ` Thiago Jung Bauermann 2008-04-17 16:02 ` Daniel Jacobowitz 2008-04-30 23:31 ` Daniel Jacobowitz 4 siblings, 1 reply; 10+ messages in thread From: Thiago Jung Bauermann @ 2008-04-07 19:34 UTC (permalink / raw) To: Daniel Jacobowitz; +Cc: gdb-patches On Mon, 2008-03-31 at 18:10 -0400, Daniel Jacobowitz wrote: > 2008-03-31 Daniel Jacobowitz <dan@codesourcery.com> > > Convert frame unwinders to use the current frame and > "struct value". My two cents. > + /* Offsets are not supported here; lazy register values must > + refer to the entire register. */ > + gdb_assert (value_offset (val) == 0); Is this a limitation of the current implementation or is there an underlying reason for it? > + while (VALUE_LVAL (new_val) == lval_register > + && value_lazy (new_val)) > + { The conditions in the while loop above fit in one line. > + frame = frame_find_by_id (VALUE_FRAME_ID (new_val)); I thought it was strange that VALUE_FRAME_ID expands to a deprecated function, since it plays such an important role in the new world order... Do you know why it is deprecated? > +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); This code assumes the register type is TYPE_CODE_PTR, right? Does it make sense to put an assertion here? > + /* Use an architecture specific method to extract the this frame's > + dummy ID, assuming it is a dummy frame. */ > + this_id = gdbarch_dummy_id (get_frame_arch (this_frame), this_frame); s/the this/this/ > +@section Selecting an 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. What about changing the last sentence to "The first sniffer returning non-zero will have its corresponding unwinder assigned to the frame."? > +@section Unwinding the 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. This looks like a good place to explain the motivation behind frame IDs. What about the following? Every time the inferior stops, 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}. This is why frame IDs are necessary, they provide a stable reference to a frame, even when the unwinder needs to find it again and generate a new @code{struct frame_info} for it. > +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. Is this a good place to list the other reasons to stop frame unwinding? E.g.: In addition, @value{GDBN} will stop unwinding after this frame if its ID is inner to the next younger frame (i.e, the unwind is going backwards in the stack frame), if its ID is equal to the ID of the next younger frame, or if the unwinder was not able to find a saved program counter. -- []'s Thiago Jung Bauermann Software Engineer IBM Linux Technology Center ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC 2/5] Frame unwinding using struct value 2008-04-07 19:34 ` Thiago Jung Bauermann @ 2008-04-17 16:02 ` Daniel Jacobowitz 0 siblings, 0 replies; 10+ messages in thread From: Daniel Jacobowitz @ 2008-04-17 16:02 UTC (permalink / raw) To: Thiago Jung Bauermann; +Cc: gdb-patches On Mon, Apr 07, 2008 at 10:58:26AM -0300, Thiago Jung Bauermann wrote: > My two cents. Much appreciated. > > + /* Offsets are not supported here; lazy register values must > > + refer to the entire register. */ > > + gdb_assert (value_offset (val) == 0); > > Is this a limitation of the current implementation or is there an > underlying reason for it? You could call it either one. I didn't add support for lazy registers containing offsets because I don't think it's useful; lazy registers are currently aimed to support unwinding, not to generally suppress target fetches the way lazy memory values do. And it keeps things simpler if we know we've got the whole register. So I've disallowed it, and that way it will be clear where to start from if we want this later. > The conditions in the while loop above fit in one line. So it does. > > + frame = frame_find_by_id (VALUE_FRAME_ID (new_val)); > > I thought it was strange that VALUE_FRAME_ID expands to a deprecated > function, since it plays such an important role in the new world > order... Do you know why it is deprecated? It's deprecated because it's writable. If it returned a read-only copy of the frame ID, then there'd be no need to deprecate it; this was added when struct value was moved from value.h to value.c. Things like: findvar.c: VALUE_FRAME_ID (reg_val) = get_frame_id (frame); Perhaps we need some new constructors. > > +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); > > This code assumes the register type is TYPE_CODE_PTR, right? > Does it make sense to put an assertion here? No, I don't think so. It will work OK for integers, too, and the assertion could be triggered by bad debug information. I don't like to add asserts where a corrupt file could trigger them, unless the alternative is crashing. > s/the this/this/ Fixed. > > +The first time a sniffer returns non-zero, the corresponding unwinder > > +is assigned to the frame. > > What about changing the last sentence to "The first sniffer returning > non-zero will have its corresponding unwinder assigned to the frame."? I don't think either is particularly clearer. > This looks like a good place to explain the motivation behind frame IDs. > What about the following? Thanks. I changed the wording a little, but basically used this. > Is this a good place to list the other reasons to stop frame unwinding? I'm not sure, so I've left it out for now. -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC 2/5] Frame unwinding using struct value 2008-03-31 22:12 [RFC 2/5] Frame unwinding using struct value Daniel Jacobowitz ` (3 preceding siblings ...) 2008-04-07 19:34 ` Thiago Jung Bauermann @ 2008-04-30 23:31 ` Daniel Jacobowitz [not found] ` <20080430230012.GB3801@adacore.com> 4 siblings, 1 reply; 10+ messages in thread From: Daniel Jacobowitz @ 2008-04-30 23:31 UTC (permalink / raw) To: gdb-patches On Mon, Mar 31, 2008 at 06:10:24PM -0400, Daniel Jacobowitz wrote: > The meat of the conversion. This patch converts frame.c, all the > related frame-unwind and frame-base code, and the dummy and sentinel > unwinders. It also includes helpers for writing new prev_register > methods and a gdbint chapter. I have now checked in the five patches I posted. This was the only one to be revised since posting, so here it is again. I've tested on i386, amd64, arm (patch coming), and mips (patch coming). I am not planning to immediately convert the remaining targets myself. But I'm glad to help anyone that has questions, and I've set up a Wiki page with some additional notes and the list of remaining targets: http://sourceware.org/gdb/wiki/ValueBasedUnwinder Any that are still left before the next release, I will do mechanically. -- Daniel Jacobowitz CodeSourcery 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> * 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. --- gdb/Makefile.in | 3 gdb/doc/gdbint.texinfo | 172 +++++++++++++++++++++++++++++----------- gdb/dummy-frame.c | 53 +++++------- gdb/frame-base.c | 17 +-- gdb/frame-base.h | 18 ++-- gdb/frame-unwind.c | 136 +++++++++++++++++++++++++------ gdb/frame-unwind.h | 109 ++++++++++++++----------- gdb/frame.c | 210 ++++++++++++++++++++++++++++++++----------------- gdb/frame.h | 18 +++- gdb/gdbarch.c | 36 ++++---- gdb/gdbarch.h | 10 +- gdb/gdbarch.sh | 4 gdb/ia64-tdep.c | 1 gdb/infcall.c | 6 - gdb/libunwind-frame.c | 1 gdb/sentinel-frame.c | 54 ++++-------- gdb/valops.c | 91 +++++++++++++++++---- 17 files changed, 619 insertions(+), 320 deletions(-) Index: src/gdb/frame.c =================================================================== --- src.orig/gdb/frame.c 2008-04-17 11:09:04.000000000 -0400 +++ src/gdb/frame.c 2008-04-17 11:29:36.000000000 -0400 @@ -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 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 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 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); - - /* Find the unwinder. */ - if (frame->unwind == NULL) - frame->unwind = frame_unwind_find_by_frame (frame->next, - &frame->prologue_cache); + value = frame_unwind_register_value (frame, regnum); - /* 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); + gdb_assert (value != NULL); - 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"); - } + *optimizedp = value_optimized_out (value); + *lvalp = VALUE_LVAL (value); + *addrp = VALUE_ADDRESS (value); + *realnump = VALUE_REGNUM (value); + + 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 *f 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_A /* 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_inf /* 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_i /* 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_inf /* 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_st } } +/* 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; Index: src/gdb/frame.h =================================================================== --- src.orig/gdb/frame.h 2008-04-17 11:09:04.000000000 -0400 +++ src/gdb/frame.h 2008-04-17 11:16:19.000000000 -0400 @@ -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 (struc /* 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_ 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): Index: src/gdb/frame-unwind.h =================================================================== --- src.orig/gdb/frame-unwind.h 2008-04-17 11:09:04.000000000 -0400 +++ src/gdb/frame-unwind.h 2008-04-17 11:16:19.000000000 -0400 @@ -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 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) (stru 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. - - 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. + 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). + + 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 Index: src/gdb/frame-base.h =================================================================== --- src.orig/gdb/frame-base.h 2008-04-17 11:09:04.000000000 -0400 +++ src/gdb/frame-base.h 2008-04-17 11:16:19.000000000 -0400 @@ -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 (stru /* 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 Index: src/gdb/valops.c =================================================================== --- src.orig/gdb/valops.c 2008-04-17 11:11:41.000000000 -0400 +++ src/gdb/valops.c 2008-04-17 11:32:53.000000000 -0400 @@ -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)); - - /* Get the data. */ - if (!get_frame_register_bytes (frame, regnum, value_offset (val), - TYPE_LENGTH (value_type (val)), - value_contents_raw (val))) + 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); + } + + /* 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."); Index: src/gdb/sentinel-frame.c =================================================================== --- src.orig/gdb/sentinel-frame.c 2008-04-17 11:09:04.000000000 -0400 +++ src/gdb/sentinel-frame.c 2008-04-17 11:16:19.000000000 -0400 @@ -42,34 +42,31 @@ sentinel_frame_cache (struct regcache *r /* 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_inf 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; Index: src/gdb/ia64-tdep.c =================================================================== --- src.orig/gdb/ia64-tdep.c 2008-04-17 11:09:20.000000000 -0400 +++ src/gdb/ia64-tdep.c 2008-04-17 11:16:19.000000000 -0400 @@ -2796,7 +2796,6 @@ static const struct frame_unwind ia64_li ia64_libunwind_frame_prev_register, NULL, NULL, - NULL, libunwind_frame_dealloc_cache }; Index: src/gdb/libunwind-frame.c =================================================================== --- src.orig/gdb/libunwind-frame.c 2008-04-17 11:09:04.000000000 -0400 +++ src/gdb/libunwind-frame.c 2008-04-17 11:16:19.000000000 -0400 @@ -214,7 +214,6 @@ static const struct frame_unwind libunwi libunwind_frame_prev_register, NULL, NULL, - NULL, libunwind_frame_dealloc_cache }; Index: src/gdb/frame-unwind.c =================================================================== --- src.orig/gdb/frame-unwind.c 2008-04-17 11:09:04.000000000 -0400 +++ src/gdb/frame-unwind.c 2008-04-17 11:16:19.000000000 -0400 @@ -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 *obsta } 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 gd (*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 Index: src/gdb/dummy-frame.c =================================================================== --- src.orig/gdb/dummy-frame.c 2008-04-17 11:09:04.000000000 -0400 +++ src/gdb/dummy-frame.c 2008-04-17 11:47:56.000000000 -0400 @@ -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_ /* 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_ /* Given a call-dummy dummy-frame, return the registers. Here the register value is taken from the local copy of the register buffer. */ -static void -dummy_frame_prev_register (struct frame_info *next_frame, +static struct value * +dummy_frame_prev_register (struct frame_info *this_frame, void **this_prologue_cache, - int regnum, int *optimized, - enum lval_type *lvalp, CORE_ADDR *addrp, - int *realnum, gdb_byte *bufferp) + int regnum) { - /* The dummy-frame sniffer always fills in the cache. */ struct dummy_frame_cache *cache = (*this_prologue_cache); + struct gdbarch *gdbarch = get_frame_arch (this_frame); + struct value *reg_val; + + /* The dummy-frame sniffer always fills in the cache. */ gdb_assert (cache != NULL); /* Describe the register's location. Generic dummy frames always have the register value in an ``expression''. */ - *optimized = 0; - *lvalp = not_lval; - *addrp = 0; - *realnum = -1; + reg_val = value_zero (register_type (gdbarch, regnum), not_lval); - /* If needed, find and return the value of the register. */ - if (bufferp != NULL) - { - /* Return the actual value. */ - /* Use the regcache_cooked_read() method so that it, on the fly, - constructs either a raw or pseudo register from the raw - register cache. */ - regcache_cooked_read (cache->prev_regcache, regnum, bufferp); - } + /* Use the regcache_cooked_read() method so that it, on the fly, + constructs either a raw or pseudo register from the raw + register cache. */ + regcache_cooked_read (cache->prev_regcache, regnum, + value_contents_writeable (reg_val)); + return reg_val; } -/* Assuming that THIS frame is a dummy (remember, the NEXT and not - THIS frame is passed in), return the ID of THIS frame. That ID is +/* Assuming that THIS frame is a dummy, return the ID of THIS frame. That ID is determined by examining the NEXT frame's unwound registers using - the method unwind_dummy_id(). As a side effect, THIS dummy frame's + the method dummy_id(). As a side effect, THIS dummy frame's dummy cache is located and and saved in THIS_PROLOGUE_CACHE. */ static void -dummy_frame_this_id (struct frame_info *next_frame, +dummy_frame_this_id (struct frame_info *this_frame, void **this_prologue_cache, struct frame_id *this_id) { Index: src/gdb/gdbarch.c =================================================================== --- src.orig/gdb/gdbarch.c 2008-04-17 11:09:04.000000000 -0400 +++ src/gdb/gdbarch.c 2008-04-17 11:16:19.000000000 -0400 @@ -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, s "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, s "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 gdbarc } 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 Index: src/gdb/gdbarch.h =================================================================== --- src.orig/gdb/gdbarch.h 2008-04-17 11:09:04.000000000 -0400 +++ src/gdb/gdbarch.h 2008-04-17 11:16:19.000000000 -0400 @@ -254,13 +254,13 @@ extern void set_gdbarch_register_type (s /* 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); Index: src/gdb/gdbarch.sh =================================================================== --- src.orig/gdb/gdbarch.sh 2008-04-17 11:09:04.000000000 -0400 +++ src/gdb/gdbarch.sh 2008-04-17 11:16:19.000000000 -0400 @@ -434,8 +434,8 @@ m:const char *:register_name:int regnr:r 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 Index: src/gdb/frame-base.c =================================================================== --- src.orig/gdb/frame-base.c 2008-04-17 11:09:04.000000000 -0400 +++ src/gdb/frame-base.c 2008-04-17 11:16:19.000000000 -0400 @@ -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 * } 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; } Index: src/gdb/doc/gdbint.texinfo =================================================================== --- src.orig/gdb/doc/gdbint.texinfo 2008-04-17 11:09:04.000000000 -0400 +++ src/gdb/doc/gdbint.texinfo 2008-04-17 11:50:21.000000000 -0400 @@ -76,6 +76,7 @@ as the mechanisms that adapt @value{GDBN * Algorithms:: * User Interface:: * libgdb:: +* Stack Frames:: * Symbol Handling:: * Language Support:: * Host Definition:: @@ -273,39 +274,6 @@ cases and real-world issues. This chapt 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 p 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 @@ -3920,14 +4009,6 @@ This method replaces @w{@code{gdbarch_ca 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} @@ -4109,13 +4190,12 @@ the @code{opcodes} library (@pxref{Suppo @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 Index: src/gdb/infcall.c =================================================================== --- src.orig/gdb/infcall.c 2008-04-17 11:09:04.000000000 -0400 +++ src/gdb/infcall.c 2008-04-17 11:16:19.000000000 -0400 @@ -462,7 +462,7 @@ call_function_by_hand (struct value *fun 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 *fun 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 *fun 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; } Index: src/gdb/Makefile.in =================================================================== --- src.orig/gdb/Makefile.in 2008-04-17 11:09:19.000000000 -0400 +++ src/gdb/Makefile.in 2008-04-17 11:16:19.000000000 -0400 @@ -2142,7 +2142,8 @@ frame.o: frame.c $(defs_h) $(frame_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) \ ^ permalink raw reply [flat|nested] 10+ messages in thread
[parent not found: <20080430230012.GB3801@adacore.com>]
* Re: [RFC 2/5] Frame unwinding using struct value [not found] ` <20080430230012.GB3801@adacore.com> @ 2008-05-01 3:37 ` Daniel Jacobowitz 0 siblings, 0 replies; 10+ messages in thread From: Daniel Jacobowitz @ 2008-05-01 3:37 UTC (permalink / raw) To: gdb-patches On Wed, Apr 30, 2008 at 04:00:12PM -0700, Joel Brobecker wrote: > I've added myself for a couple of targets, and I see that Ulrich has > also added himself before I did :-). I can do a couple more after I'm > done with the ones I signed up for. Thank you both. The remaining targets should be relatively easy to update in one shot - IA64 was one of the ones I was particularly hoping you would take :-) -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2008-05-01 3:37 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-03-31 22:12 [RFC 2/5] Frame unwinding using struct value Daniel Jacobowitz
2008-04-01 13:23 ` Eli Zaretskii
2008-04-17 15:30 ` Daniel Jacobowitz
2008-04-04 19:10 ` Joel Brobecker
2008-04-17 15:59 ` Daniel Jacobowitz
2008-04-04 19:16 ` Joel Brobecker
2008-04-07 19:34 ` Thiago Jung Bauermann
2008-04-17 16:02 ` Daniel Jacobowitz
2008-04-30 23:31 ` Daniel Jacobowitz
[not found] ` <20080430230012.GB3801@adacore.com>
2008-05-01 3:37 ` Daniel Jacobowitz
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox