aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog16
-rw-r--r--gdb/dummy-frame.c49
-rw-r--r--gdb/frame-unwind.h15
-rw-r--r--gdb/frame.c20
-rw-r--r--gdb/frame.h4
-rw-r--r--gdb/infrun.c8
-rw-r--r--gdb/stack.c15
-rw-r--r--gdb/valops.c5
8 files changed, 118 insertions, 14 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 4b116ae..b383e54 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,19 @@
+2003-01-19 Andrew Cagney <ac131313@redhat.com>
+
+ * frame-unwind.h (frame_unwind_pop_ftype): Declare.
+ (struct frame_unwind): Add field pop.
+ * frame.h (frame_pop): Declare.
+ * frame.c (frame_saved_regs_pop): New function.
+ (trad_frame_unwinder): Add frame_saved_regs_pop.
+ (frame_pop): New function.
+ * dummy-frame.c (dummy_frame_pop): New function.
+ (discard_innermost_dummy): New function.
+ (generic_pop_dummy_frame): Use discard_innermost_dummy.
+ (dummy_frame_unwind): Add dummy_frame_pop.
+ * infrun.c (normal_stop): Call frame_pop instead of POP_FRAME.
+ * valops.c (hand_function_call): Ditto.
+ * stack.c (return_command): Ditto.
+
2003-01-18 Andrew Cagney <ac131313@redhat.com>
* cris-tdep.c: Fix function declaration indentation.
diff --git a/gdb/dummy-frame.c b/gdb/dummy-frame.c
index 0a3e35e..5b63830 100644
--- a/gdb/dummy-frame.c
+++ b/gdb/dummy-frame.c
@@ -270,8 +270,48 @@ generic_pop_current_frame (void (*popper) (struct frame_info * frame))
(*popper) (frame);
}
-/* Function: pop_dummy_frame
- Restore the machine state from a saved dummy stack frame. */
+/* Discard the innermost dummy frame from the dummy frame stack
+ (passed in as a parameter). */
+
+static void
+discard_innermost_dummy (struct dummy_frame **stack)
+{
+ struct dummy_frame *tbd = (*stack);
+ (*stack) = (*stack)->next;
+ regcache_xfree (tbd->regcache);
+ xfree (tbd);
+}
+
+/* Function: dummy_frame_pop. Restore the machine state from a saved
+ dummy stack frame. */
+
+static void
+dummy_frame_pop (struct frame_info *fi, void **cache,
+ struct regcache *regcache)
+{
+ struct dummy_frame *dummy = cached_find_dummy_frame (fi, cache);
+
+ /* If it isn't, what are we even doing here? */
+ gdb_assert (get_frame_type (fi) == DUMMY_FRAME);
+
+ if (dummy == NULL)
+ error ("Can't pop dummy frame!");
+
+ /* Discard all dummy frames up-to but not including this one. */
+ while (dummy_frame_stack != dummy)
+ discard_innermost_dummy (&dummy_frame_stack);
+
+ /* Restore this one. */
+ regcache_cpy (regcache, dummy->regcache);
+ flush_cached_frames ();
+
+ /* Now discard it. */
+ discard_innermost_dummy (&dummy_frame_stack);
+
+ /* Note: target changed would be better. Registers, memory and
+ frame are all invalid. */
+ flush_cached_frames ();
+}
void
generic_pop_dummy_frame (void)
@@ -283,12 +323,10 @@ generic_pop_dummy_frame (void)
if (!dummy_frame)
error ("Can't pop dummy frame!");
- dummy_frame_stack = dummy_frame->next;
regcache_cpy (current_regcache, dummy_frame->regcache);
flush_cached_frames ();
- regcache_xfree (dummy_frame->regcache);
- xfree (dummy_frame);
+ discard_innermost_dummy (&dummy_frame_stack);
}
/* Function: fix_call_dummy
@@ -369,6 +407,7 @@ dummy_frame_id_unwind (struct frame_info *frame,
static struct frame_unwind dummy_frame_unwind =
{
+ dummy_frame_pop,
dummy_frame_pc_unwind,
dummy_frame_id_unwind,
dummy_frame_register_unwind
diff --git a/gdb/frame-unwind.h b/gdb/frame-unwind.h
index 863f259..2c67c96 100644
--- a/gdb/frame-unwind.h
+++ b/gdb/frame-unwind.h
@@ -82,12 +82,27 @@ typedef void (frame_unwind_id_ftype) (struct frame_info * frame,
void **unwind_cache,
struct frame_id * id);
+/* Discard the frame by restoring the registers (in regcache) back to
+ that of the caller. */
+/* NOTE: cagney/2003-01-19: While at present the callers all pop each
+ frame in turn, the implementor should try to code things so that
+ any frame can be popped directly. */
+/* FIXME: cagney/2003-01-19: Since both FRAME and REGCACHE refer to a
+ common register cache, care must be taken when restoring the
+ registers. The `correct fix' is to first first save the registers
+ in a scratch cache, and second write that scratch cache back to to
+ the real register cache. */
+
+typedef void (frame_unwind_pop_ftype) (struct frame_info *frame,
+ void **unwind_cache,
+ struct regcache *regcache);
struct frame_unwind
{
/* Should the frame's type go here? */
/* Should an attribute indicating the frame's address-in-block go
here? */
+ frame_unwind_pop_ftype *pop;
frame_unwind_pc_ftype *pc;
frame_unwind_id_ftype *id;
frame_unwind_reg_ftype *reg;
diff --git a/gdb/frame.c b/gdb/frame.c
index f85b54a..9fb5e9b 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -145,6 +145,18 @@ frame_id_unwind (struct frame_info *frame)
return frame->id_unwind_cache;
}
+void
+frame_pop (struct frame_info *frame)
+{
+ /* FIXME: cagney/2003-01-18: There is probably a chicken-egg problem
+ with passing in current_regcache. The pop function needs to be
+ written carefully so as to not overwrite registers whose [old]
+ values are needed to restore other registers. Instead, this code
+ should pass in a scratch cache and, as a second step, restore the
+ registers using that. */
+ frame->unwind->pop (frame, &frame->unwind_cache, current_regcache);
+ flush_cached_frames ();
+}
void
frame_register_unwind (struct frame_info *frame, int regnum,
@@ -715,7 +727,15 @@ frame_saved_regs_id_unwind (struct frame_info *next_frame, void **cache,
id->base = base;
}
+static void
+frame_saved_regs_pop (struct frame_info *fi, void **cache,
+ struct regcache *regcache)
+{
+ POP_FRAME;
+}
+
const struct frame_unwind trad_frame_unwinder = {
+ frame_saved_regs_pop,
frame_saved_regs_pc_unwind,
frame_saved_regs_id_unwind,
frame_saved_regs_register_unwind
diff --git a/gdb/frame.h b/gdb/frame.h
index 9cbdaa4..64f932a 100644
--- a/gdb/frame.h
+++ b/gdb/frame.h
@@ -306,6 +306,10 @@ extern CORE_ADDR frame_pc_unwind (struct frame_info *frame);
caller's frame. */
extern struct frame_id frame_id_unwind (struct frame_info *frame);
+/* Discard the specified frame. Restoring the registers to the state
+ of the caller. */
+extern void frame_pop (struct frame_info *frame);
+
/* Describe the saved registers of a frame. */
#if defined (EXTRA_FRAME_INFO) || defined (FRAME_FIND_SAVED_REGS)
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 9f94aeb..29ebf44 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -3109,10 +3109,10 @@ normal_stop (void)
if (stop_stack_dummy)
{
- /* Pop the empty frame that contains the stack dummy.
- POP_FRAME ends with a setting of the current frame, so we
- can use that next. */
- POP_FRAME;
+ /* Pop the empty frame that contains the stack dummy. POP_FRAME
+ ends with a setting of the current frame, so we can use that
+ next. */
+ frame_pop (get_current_frame ());
/* Set stop_pc to what it was before we called the function.
Can't rely on restore_inferior_status because that only gets
called if we don't stop in the called function. */
diff --git a/gdb/stack.c b/gdb/stack.c
index b48dec7..405a5e4 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -1625,6 +1625,10 @@ return_command (char *retval_exp, int from_tty)
error ("Not confirmed.");
}
+ /* FIXME: cagney/2003-01-18: Rather than pop each frame in turn,
+ this code should just go straight to the relevant frame and pop
+ that. */
+
/* Do the real work. Pop until the specified frame is current. We
use this method because the deprecated_selected_frame is not valid after
a POP_FRAME. The pc comparison makes this work even if the
@@ -1632,11 +1636,11 @@ return_command (char *retval_exp, int from_tty)
while (selected_frame_addr != get_frame_base (frame = get_current_frame ())
|| selected_frame_pc != get_frame_pc (frame))
- POP_FRAME;
+ frame_pop (get_current_frame ());
/* Then pop that frame. */
- POP_FRAME;
+ frame_pop (get_current_frame ());
/* Compute the return value (if any) and store in the place
for return values. */
@@ -1646,9 +1650,14 @@ return_command (char *retval_exp, int from_tty)
/* If we are at the end of a call dummy now, pop the dummy frame too. */
+ /* FIXME: cagney/2003-01-18: This is silly. Instead of popping all
+ the frames except the dummy, and then, as an afterthought,
+ popping the dummy frame, this code should just pop through to the
+ dummy frame. */
+
if (CALL_DUMMY_HAS_COMPLETED (read_pc(), read_sp (),
get_frame_base (get_current_frame ())))
- POP_FRAME;
+ frame_pop (get_current_frame ());
/* If interactive, print the frame that is now current. */
diff --git a/gdb/valops.c b/gdb/valops.c
index d3906f9f..d1a1877 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -1711,8 +1711,9 @@ You must use a pointer to function type variable. Command ignored.", arg_name);
{
/* The user wants the context restored. */
- /* We must get back to the frame we were before the dummy call. */
- POP_FRAME;
+ /* We must get back to the frame we were before the dummy
+ call. */
+ frame_pop (get_current_frame ());
/* FIXME: Insert a bunch of wrap_here; name can be very long if it's
a C++ name with arguments and stuff. */