2003-01-19 Andrew Cagney <ac131313@redhat.com>
authorAndrew Cagney <cagney@redhat.com>
Sun, 19 Jan 2003 17:39:16 +0000 (17:39 +0000)
committerAndrew Cagney <cagney@redhat.com>
Sun, 19 Jan 2003 17:39:16 +0000 (17:39 +0000)
* 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.

gdb/ChangeLog
gdb/dummy-frame.c
gdb/frame-unwind.h
gdb/frame.c
gdb/frame.h
gdb/infrun.c
gdb/stack.c
gdb/valops.c

index 4b116ae..b383e54 100644 (file)
@@ -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.
index 0a3e35e..5b63830 100644 (file)
@@ -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
index 863f259..2c67c96 100644 (file)
@@ -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;
index f85b54a..9fb5e9b 100644 (file)
@@ -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
index 9cbdaa4..64f932a 100644 (file)
@@ -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)
index 9f94aeb..29ebf44 100644 (file)
@@ -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.  */
index b48dec7..405a5e4 100644 (file)
@@ -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.  */
 
index d3906f9..d1a1877 100644 (file)
@@ -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.  */