This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
[patch/rfc] frame_id_unwind()
- From: Andrew Cagney <ac131313 at redhat dot com>
- To: gdb-patches at sources dot redhat dot com
- Date: Wed, 11 Dec 2002 16:11:10 -0500
- Subject: [patch/rfc] frame_id_unwind()
Hello,
The attached patch adds a mechanism for unwinding the frame ID. A frame
ID uniquely identifies a frame. It also, unlike the frame chain, has
room to expand so that it can accomodate more than one stack pointer.
For the moment the patch sets up the frame_id_unwind() code but doesn't
use it. That will come shortly when I go to commit the code that
unwinds the PC before anything else.
I'll look to commit in a few days,
Andrew
2002-12-11 Andrew Cagney <ac131313@redhat.com>
* frame.h (frame_id_unwind): Declare.
(struct frame_info): Add fields id_unwind, id_unwind_cache_p and
id_unwind_cache.
(frame_id_unwind_ftype): Declare.
* frame.c (frame_id_unwind): New function.
(set_unwind_by_pc): Add unwind_id parameter. Initialized.
(create_new_frame, get_prev_frame): Pass in id_unwind.
(frame_saved_regs_id_unwind): New function.
(frame_saved_regs_id_unwind): New function.
* dummy-frame.c (dummy_frame_id_unwind): New function.
(struct dummy_frame): Add field id.
(generic_push_dummy_frame): Initialize `id'.
* dummy-frame.h (dummy_frame_id_unwind): Declare.
Index: dummy-frame.c
===================================================================
RCS file: /cvs/src/src/gdb/dummy-frame.c,v
retrieving revision 1.6
diff -u -r1.6 dummy-frame.c
--- dummy-frame.c 9 Dec 2002 03:30:44 -0000 1.6
+++ dummy-frame.c 11 Dec 2002 21:03:05 -0000
@@ -43,6 +43,7 @@
CORE_ADDR fp;
CORE_ADDR sp;
CORE_ADDR top;
+ struct frame_id id;
struct regcache *regcache;
/* Address range of the call dummy code. Look for PC in the range
@@ -232,6 +233,7 @@
dummy_frame->sp = read_sp ();
dummy_frame->top = 0;
dummy_frame->fp = fp;
+ dummy_frame->id = get_frame_id (get_current_frame ());
regcache_cpy (dummy_frame->regcache, current_regcache);
dummy_frame->next = dummy_frame_stack;
dummy_frame_stack = dummy_frame;
@@ -340,5 +342,19 @@
if (dummy == NULL)
return 0;
return dummy->pc;
+}
+
+
+struct frame_id
+dummy_frame_id_unwind (struct frame_info *frame,
+ void **cache)
+{
+ struct dummy_frame *dummy = cached_find_dummy_frame (frame, cache);
+ /* Oops! In a dummy-frame but can't find the stack dummy. Pretend
+ that the frame doesn't unwind. Should this function instead
+ return a has-no-caller indication? */
+ if (dummy == NULL)
+ return null_frame_id;
+ return dummy->id;
}
Index: dummy-frame.h
===================================================================
RCS file: /cvs/src/src/gdb/dummy-frame.h,v
retrieving revision 1.4
diff -u -r1.4 dummy-frame.h
--- dummy-frame.h 24 Nov 2002 15:06:08 -0000 1.4
+++ dummy-frame.h 11 Dec 2002 21:03:05 -0000
@@ -60,6 +60,12 @@
extern CORE_ADDR dummy_frame_pc_unwind (struct frame_info *frame,
void **unwind_cache);
+/* Assuming that FRAME is a dummy, return the ID of the calling frame
+ (the frame that the dummy has the saved state of). */
+
+extern struct frame_id dummy_frame_id_unwind (struct frame_info *frame,
+ void **unwind_cache);
+
/* Does the PC fall in a dummy frame?
This function is used by "frame.c" when creating a new `struct
Index: frame.c
===================================================================
RCS file: /cvs/src/src/gdb/frame.c,v
retrieving revision 1.39
diff -u -r1.39 frame.c
--- frame.c 9 Dec 2002 02:04:16 -0000 1.39
+++ frame.c 11 Dec 2002 21:03:05 -0000
@@ -133,6 +133,19 @@
return frame->pc_unwind_cache;
}
+struct frame_id
+frame_id_unwind (struct frame_info *frame)
+{
+ if (!frame->id_unwind_cache_p)
+ {
+ frame->id_unwind_cache =
+ frame->id_unwind (frame, &frame->unwind_cache);
+ frame->id_unwind_cache_p = 1;
+ }
+ return frame->id_unwind_cache;
+}
+
+
void
frame_register_unwind (struct frame_info *frame, int regnum,
int *optimizedp, enum lval_type *lvalp,
@@ -638,6 +651,68 @@
return FRAME_SAVED_PC (frame);
}
+static struct frame_id
+frame_saved_regs_id_unwind (struct frame_info *next_frame, void **cache)
+{
+ int fromleaf;
+ struct frame_id id;
+
+ if (next_frame->next == NULL)
+ /* FIXME: 2002-11-09: Frameless functions can occure anywhere in
+ the frame chain, not just the inner most frame! The generic,
+ per-architecture, frame code should handle this and the below
+ should simply be removed. */
+ fromleaf = FRAMELESS_FUNCTION_INVOCATION (next_frame);
+ else
+ fromleaf = 0;
+
+ if (fromleaf)
+ /* A frameless inner-most frame. The `FP' (which isn't an
+ architecture frame-pointer register!) of the caller is the same
+ as the callee. */
+ /* FIXME: 2002-11-09: There isn't any reason to special case this
+ edge condition. Instead the per-architecture code should hande
+ it locally. */
+ id.base = get_frame_base (next_frame);
+ else
+ {
+ /* Two macros defined in tm.h specify the machine-dependent
+ actions to be performed here.
+
+ First, get the frame's chain-pointer.
+
+ If that is zero, the frame is the outermost frame or a leaf
+ called by the outermost frame. This means that if start
+ calls main without a frame, we'll return 0 (which is fine
+ anyway).
+
+ Nope; there's a problem. This also returns when the current
+ routine is a leaf of main. This is unacceptable. We move
+ this to after the ffi test; I'd rather have backtraces from
+ start go curfluy than have an abort called from main not show
+ main. */
+ id.base = FRAME_CHAIN (next_frame);
+
+ /* FIXME: cagney/2002-06-08: There should be two tests here.
+ The first would check for a valid frame chain based on a user
+ selectable policy. The default being ``stop at main'' (as
+ implemented by generic_func_frame_chain_valid()). Other
+ policies would be available - stop at NULL, .... The second
+ test, if provided by the target architecture, would check for
+ more exotic cases - most target architectures wouldn't bother
+ with this second case. */
+ if (!FRAME_CHAIN_VALID (id.base, next_frame))
+ return null_frame_id;
+ }
+ if (id.base == 0)
+ return null_frame_id;
+
+ /* FIXME: cagney/2002-06-08: This should probably return the frame's
+ function and not the PC (a.k.a. resume address). */
+ id.pc = frame_pc_unwind (next_frame);
+ return id;
+}
+
/* Function: get_saved_register
Find register number REGNUM relative to FRAME and put its (raw,
target format) contents in *RAW_BUFFER.
@@ -742,7 +817,8 @@
static void
set_unwind_by_pc (CORE_ADDR pc, CORE_ADDR fp,
frame_register_unwind_ftype **unwind_register,
- frame_pc_unwind_ftype **unwind_pc)
+ frame_pc_unwind_ftype **unwind_pc,
+ frame_id_unwind_ftype **unwind_id)
{
if (!DEPRECATED_USE_GENERIC_DUMMY_FRAMES)
{
@@ -752,6 +828,7 @@
return vaguely correct values.. */
*unwind_register = frame_saved_regs_register_unwind;
*unwind_pc = frame_saved_regs_pc_unwind;
+ *unwind_id = frame_saved_regs_id_unwind;
}
else if (DEPRECATED_PC_IN_CALL_DUMMY_P ()
? DEPRECATED_PC_IN_CALL_DUMMY (pc, 0, 0)
@@ -759,11 +836,13 @@
{
*unwind_register = dummy_frame_register_unwind;
*unwind_pc = dummy_frame_pc_unwind;
+ *unwind_id = dummy_frame_id_unwind;
}
else
{
*unwind_register = frame_saved_regs_register_unwind;
*unwind_pc = frame_saved_regs_pc_unwind;
+ *unwind_id = frame_saved_regs_id_unwind;
}
}
@@ -815,7 +894,7 @@
/* Select/initialize an unwind function. */
set_unwind_by_pc (fi->pc, fi->frame, &fi->register_unwind,
- &fi->pc_unwind);
+ &fi->pc_unwind, &fi->id_unwind);
return fi;
}
@@ -1069,7 +1148,7 @@
check things like the debug info at that point (dwarf2cfi?) and
use that to decide how the frame should be unwound. */
set_unwind_by_pc (prev->pc, prev->frame, &prev->register_unwind,
- &prev->pc_unwind);
+ &prev->pc_unwind, &prev->id_unwind);
/* NOTE: cagney/2002-11-18: The code segments, found in
create_new_frame and get_prev_frame(), that initializes the
Index: frame.h
===================================================================
RCS file: /cvs/src/src/gdb/frame.h,v
retrieving revision 1.44
diff -u -r1.44 frame.h
--- frame.h 4 Dec 2002 00:05:53 -0000 1.44
+++ frame.h 11 Dec 2002 21:03:06 -0000
@@ -298,6 +298,10 @@
extern CORE_ADDR frame_pc_unwind (struct frame_info *frame);
+/* Unwind the frame ID. Return an ID that uniquely identifies the
+ caller's frame. */
+extern struct frame_id frame_id_unwind (struct frame_info *frame);
+
/* Return the location (and possibly value) of REGNUM for the previous
(older, up) frame. All parameters except VALUEP can be assumed to
@@ -328,6 +332,12 @@
typedef CORE_ADDR (frame_pc_unwind_ftype) (struct frame_info *frame,
void **unwind_cache);
+/* Same as for registers above, but return the ID of the frame that
+ called this one. */
+
+typedef struct frame_info (frame_id_unwind_ftype) (struct frame_info *frame,
+ void **unwind_cache);
+
/* Describe the saved registers of a frame. */
#if defined (EXTRA_FRAME_INFO) || defined (FRAME_FIND_SAVED_REGS)
@@ -423,6 +433,12 @@
frame_pc_unwind_ftype *pc_unwind;
int pc_unwind_cache_p;
CORE_ADDR pc_unwind_cache;
+
+ /* See description above. The previous frame's resume address.
+ Save the previous PC in a local cache. */
+ frame_id_unwind_ftype *id_unwind;
+ int id_unwind_cache_p;
+ struct frame_id id_unwind_cache;
/* Pointers to the next (down, inner, younger) and previous (up,
outer, older) frame_info's in the frame cache. */