2003-03-14 Andrew Cagney <cagney@redhat.com>
authorAndrew Cagney <cagney@redhat.com>
Fri, 14 Mar 2003 20:34:14 +0000 (20:34 +0000)
committerAndrew Cagney <cagney@redhat.com>
Fri, 14 Mar 2003 20:34:14 +0000 (20:34 +0000)
* frame.c (get_prev_frame): When a legacy frame, always call
legacy_get_prev_frame.  Simplify unwind code using assumption that
the unwinder is new.
(legacy_get_prev_frame): Handle legacy sentinel frame unwind here.
(legacy_frame_p): When no gdbarch_unwind_dummy_id, or
SAVED_DUMMY_FRAME_TOS, assume a legacy frame.

gdb/ChangeLog
gdb/frame.c

index bd123a17ddc10fb939f0df50b408b19add016539..ae39b61c3793d1f692d4004b5be79901008d6e05 100644 (file)
@@ -1,3 +1,12 @@
+2003-03-14  Andrew Cagney  <cagney@redhat.com>
+
+       * frame.c (get_prev_frame): When a legacy frame, always call
+       legacy_get_prev_frame.  Simplify unwind code using assumption that
+       the unwinder is new.
+       (legacy_get_prev_frame): Handle legacy sentinel frame unwind here.
+       (legacy_frame_p): When no gdbarch_unwind_dummy_id, or
+       SAVED_DUMMY_FRAME_TOS, assume a legacy frame.
+
 2003-03-14  Andrew Cagney  <cagney@redhat.com>
 
        * frame.c (get_saved_register): Delete function.
index 26e80beca97ad1c98eff30a3914b435e254212e2..cf9349d658c24f46fdbb831cb8f8a308f2e3662f 100644 (file)
@@ -992,6 +992,142 @@ legacy_get_prev_frame (struct frame_info *this_frame)
   struct frame_info *prev;
   int fromleaf;
 
+  /* Allocate the new frame but do not wire it in to the frame chain.
+     Some (bad) code in INIT_FRAME_EXTRA_INFO tries to look along
+     frame->next to pull some fancy tricks (of course such code is, by
+     definition, recursive).  Try to prevent it.
+
+     There is no reason to worry about memory leaks, should the
+     remainder of the function fail.  The allocated memory will be
+     quickly reclaimed when the frame cache is flushed, and the `we've
+     been here before' check, in get_prev_frame will stop repeated
+     memory allocation calls.  */
+  prev = FRAME_OBSTACK_ZALLOC (struct frame_info);
+  prev->level = this_frame->level + 1;
+
+  /* NOTE: cagney/2002-11-18: Should have been correctly setting the
+     frame's type here, before anything else, and not last, at the
+     bottom of this function.  The various
+     DEPRECATED_INIT_EXTRA_FRAME_INFO, DEPRECATED_INIT_FRAME_PC,
+     DEPRECATED_INIT_FRAME_PC_FIRST and
+     DEPRECATED_FRAME_INIT_SAVED_REGS methods are full of work-arounds
+     that handle the frame not being correctly set from the start.
+     Unfortunatly those same work-arounds rely on the type defaulting
+     to NORMAL_FRAME.  Ulgh!  The new frame code does not have this
+     problem.  */
+  prev->type = NORMAL_FRAME;
+
+  /* Handle sentinel frame unwind as a special case.  */
+  if (this_frame->level < 0)
+    {
+      /* Try to unwind the PC.  If that doesn't work, assume we've reached
+        the oldest frame and simply return.  Is there a better sentinal
+        value?  The unwound PC value is then used to initialize the new
+        previous frame's type.
+
+        Note that the pc-unwind is intentionally performed before the
+        frame chain.  This is ok since, for old targets, both
+        frame_pc_unwind (nee, FRAME_SAVED_PC) and FRAME_CHAIN()) assume
+        THIS_FRAME's data structures have already been initialized (using
+        DEPRECATED_INIT_EXTRA_FRAME_INFO) and hence the call order
+        doesn't matter.
+        
+        By unwinding the PC first, it becomes possible to, in the case of
+        a dummy frame, avoid also unwinding the frame ID.  This is
+        because (well ignoring the PPC) a dummy frame can be located
+        using THIS_FRAME's frame ID.  */
+      
+      prev->pc = frame_pc_unwind (this_frame);
+      if (prev->pc == 0)
+       {
+         /* The allocated PREV_FRAME will be reclaimed when the frame
+            obstack is next purged.  */
+         if (frame_debug)
+           fprintf_unfiltered (gdb_stdlog,
+                               "Outermost frame - unwound PC zero\n");
+         return NULL;
+       }
+      prev->type = frame_type_from_pc (prev->pc);
+
+      /* Set the unwind functions based on that identified PC.  */
+      prev->unwind = frame_unwind_find_by_pc (current_gdbarch, prev->pc);
+
+      /* Find the prev's frame's ID.  */
+      if (prev->type == DUMMY_FRAME
+         && gdbarch_unwind_dummy_id_p (current_gdbarch))
+       {
+         /* When unwinding a normal frame, the stack structure is
+            determined by analyzing the frame's function's code (be
+            it using brute force prologue analysis, or the dwarf2
+            CFI).  In the case of a dummy frame, that simply isn't
+            possible.  The The PC is either the program entry point,
+            or some random address on the stack.  Trying to use that
+            PC to apply standard frame ID unwind techniques is just
+            asking for trouble.  */
+         /* Assume hand_function_call(), via SAVE_DUMMY_FRAME_TOS,
+            previously saved the dummy frame's ID.  Things only work
+            if the two return the same value.  */
+         gdb_assert (SAVE_DUMMY_FRAME_TOS_P ());
+         /* 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.  */
+         prev->id = gdbarch_unwind_dummy_id (current_gdbarch, this_frame);
+       }
+      else
+       {
+         /* We're unwinding a sentinel frame, the PC of which is
+            pointing at a stack dummy.  Fake up the dummy frame's ID
+            using the same sequence as is found a traditional
+            unwinder.  Once all architectures supply the
+            unwind_dummy_id method, this code can go away.  */
+         prev->id.base = read_fp ();
+         prev->id.pc = read_pc ();
+       }
+
+      /* Check that the unwound ID is valid.  */
+      if (!frame_id_p (prev->id))
+       {
+         if (frame_debug)
+           fprintf_unfiltered (gdb_stdlog,
+                               "Outermost legacy sentinel frame - unwound frame ID invalid\n");
+         return NULL;
+       }
+
+      /* Check that the new frame isn't inner to (younger, below,
+        next) the old frame.  If that happens the frame unwind is
+        going backwards.  */
+      /* FIXME: cagney/2003-02-25: Ignore the sentinel frame since
+        that doesn't have a valid frame ID.  Should instead set the
+        sentinel frame's frame ID to a `sentinel'.  Leave it until
+        after the switch to storing the frame ID, instead of the
+        frame base, in the frame object.  */
+
+      /* FIXME: cagney/2002-12-18: Instead of this hack, should only
+        store the frame ID in PREV_FRAME.  Unfortunatly, some
+        architectures (HP/UX) still reply on EXTRA_FRAME_INFO and,
+        hence, still poke at the "struct frame_info" object directly.  */
+      prev->frame = prev->id.base;
+
+      /* Link it in.  */
+      this_frame->prev = prev;
+      prev->next = this_frame;
+
+      /* FIXME: cagney/2002-01-19: This call will go away.  Instead of
+        initializing extra info, all frames will use the frame_cache
+        (passed to the unwind functions) to store additional frame
+        info.  Unfortunatly legacy targets can't use
+        legacy_get_prev_frame() to unwind the sentinel frame and,
+        consequently, are forced to take this code path and rely on
+        the below call to DEPRECATED_INIT_EXTRA_FRAME_INFO to
+        initialize the inner-most frame.  */
+      if (DEPRECATED_INIT_EXTRA_FRAME_INFO_P ())
+       {
+         DEPRECATED_INIT_EXTRA_FRAME_INFO (0, prev);
+       }
+      return prev;
+    }
+
   /* This code only works on normal frames.  A sentinel frame, where
      the level is -1, should never reach this code.  */
   gdb_assert (this_frame->level >= 0);
@@ -1048,19 +1184,10 @@ legacy_get_prev_frame (struct frame_info *this_frame)
   if (address == 0)
     return 0;
 
-  /* Create an initially zero previous frame.  */
-  prev = frame_obstack_zalloc (sizeof (struct frame_info));
-
-  /* Link it in.  */
+  /* Link in the already allocated prev frame.  */
   this_frame->prev = prev;
   prev->next = this_frame;
   prev->frame = address;
-  prev->level = this_frame->level + 1;
-  /* FIXME: cagney/2002-11-18: Should be setting the frame's type
-     here, before anything else, and not last.  Various INIT functions
-     are full of work-arounds for the frames type not being set
-     correctly from the word go.  Ulgh!  */
-  prev->type = NORMAL_FRAME;
 
   /* This change should not be needed, FIXME!  We should determine
      whether any targets *need* DEPRECATED_INIT_FRAME_PC to happen
@@ -1305,11 +1432,8 @@ get_prev_frame (struct frame_info *this_frame)
     }
 
   /* If any of the old frame initialization methods are around, use
-     the legacy get_prev_frame method.  Just don't try to unwind a
-     sentinel frame using that method - it doesn't work.  All sentinal
-     frames use the new unwind code.  */
-  if (legacy_frame_p (current_gdbarch)
-      && this_frame->level >= 0)
+     the legacy get_prev_frame method.  */
+  if (legacy_frame_p (current_gdbarch))
     {
       prev_frame = legacy_get_prev_frame (this_frame);
       if (frame_debug && prev_frame == NULL)
@@ -1376,39 +1500,16 @@ get_prev_frame (struct frame_info *this_frame)
         address on the stack.  Trying to use that PC to apply
         standard frame ID unwind techniques is just asking for
         trouble.  */
-      if (gdbarch_unwind_dummy_id_p (current_gdbarch))
-       {
-         /* Assume hand_function_call(), via SAVE_DUMMY_FRAME_TOS,
-            previously saved the dummy frame's ID.  Things only work
-            if the two return the same value.  */
-         gdb_assert (SAVE_DUMMY_FRAME_TOS_P ());
-         /* 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.  */
-         prev_frame->id = gdbarch_unwind_dummy_id (current_gdbarch,
-                                                   this_frame);
-       }
-      else if (this_frame->level < 0)
-       {
-         /* We're unwinding a sentinel frame, the PC of which is
-            pointing at a stack dummy.  Fake up the dummy frame's ID
-            using the same sequence as is found a traditional
-            unwinder.  Once all architectures supply the
-            unwind_dummy_id method, this code can go away.  */
-         prev_frame->id.base = read_fp ();
-         prev_frame->id.pc = read_pc ();
-       }
-      else
-       {
-         /* Outch!  We're not on the innermost frame yet we're trying
-            to unwind to a dummy.  The architecture must provide the
-            unwind_dummy_id() method.  Abandon the unwind process but
-            only after first warning the user.  */
-         internal_warning (__FILE__, __LINE__,
-                           "Missing unwind_dummy_id architecture method");
-         return NULL;
-       }
+      gdb_assert (gdbarch_unwind_dummy_id_p (current_gdbarch));
+       /* Assume hand_function_call(), via SAVE_DUMMY_FRAME_TOS,
+          previously saved the dummy frame's ID.  Things only work if
+          the two return the same value.  */
+      gdb_assert (SAVE_DUMMY_FRAME_TOS_P ());
+      /* 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.  */
+      prev_frame->id = gdbarch_unwind_dummy_id (current_gdbarch, this_frame);
       break;
     case NORMAL_FRAME:
     case SIGTRAMP_FRAME:
@@ -1455,20 +1556,6 @@ get_prev_frame (struct frame_info *this_frame)
   this_frame->prev = prev_frame;
   prev_frame->next = this_frame;
 
-  /* FIXME: cagney/2002-01-19: This call will go away.  Instead of
-     initializing extra info, all frames will use the frame_cache
-     (passed to the unwind functions) to store additional frame info.
-     Unfortunatly legacy targets can't use legacy_get_prev_frame() to
-     unwind the sentinel frame and, consequently, are forced to take
-     this code path and rely on the below call to
-     DEPRECATED_INIT_EXTRA_FRAME_INFO to initialize the inner-most
-     frame.  */
-  if (DEPRECATED_INIT_EXTRA_FRAME_INFO_P ())
-    {
-      gdb_assert (prev_frame->level == 0);
-      DEPRECATED_INIT_EXTRA_FRAME_INFO (0, prev_frame);
-    }
-
   return prev_frame;
 }
 
@@ -1680,7 +1767,9 @@ legacy_frame_p (struct gdbarch *current_gdbarch)
   return (DEPRECATED_INIT_FRAME_PC_P ()
          || DEPRECATED_INIT_FRAME_PC_FIRST_P ()
          || DEPRECATED_INIT_EXTRA_FRAME_INFO_P ()
-         || FRAME_CHAIN_P ());
+         || FRAME_CHAIN_P ()
+         || !gdbarch_unwind_dummy_id_p (current_gdbarch)
+         || !SAVE_DUMMY_FRAME_TOS_P ());
 }
 
 void