2003-04-09 Andrew Cagney <cagney@redhat.com>
[deliverable/binutils-gdb.git] / gdb / frame.c
index 99b3108ce237254719e74985b7185c9b10773d14..38ce5ee73e57fb8d75ab4927da5034e12ee2327d 100644 (file)
@@ -36,6 +36,7 @@
 #include "annotate.h"
 #include "language.h"
 #include "frame-unwind.h"
+#include "frame-base.h"
 #include "command.h"
 #include "gdbcmd.h"
 
@@ -63,13 +64,8 @@ get_frame_id (struct frame_info *fi)
       /* Find THIS frame's ID.  */
       fi->unwind->this_id (fi->next, &fi->prologue_cache, &fi->id);
       fi->id_p = 1;
-      /* 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.  */
-      fi->frame = fi->id.base;
     }
-  return frame_id_build (fi->frame, fi->pc);
+  return frame_id_build (fi->id.base, get_frame_pc (fi));
 }
 
 const struct frame_id null_frame_id; /* All zeros.  */
@@ -143,7 +139,7 @@ frame_find_by_id (struct frame_id id)
 CORE_ADDR
 frame_pc_unwind (struct frame_info *this_frame)
 {
-  if (!this_frame->pc_unwind_cache_p)
+  if (!this_frame->prev_pc.p)
     {
       CORE_ADDR pc;
       if (gdbarch_unwind_pc_p (current_gdbarch))
@@ -185,10 +181,27 @@ frame_pc_unwind (struct frame_info *this_frame)
        }
       else
        internal_error (__FILE__, __LINE__, "No gdbarch_unwind_pc method");
-      this_frame->pc_unwind_cache = pc;
-      this_frame->pc_unwind_cache_p = 1;
+      this_frame->prev_pc.value = pc;
+      this_frame->prev_pc.p = 1;
     }
-  return this_frame->pc_unwind_cache;
+  return this_frame->prev_pc.value;
+}
+
+CORE_ADDR
+frame_func_unwind (struct frame_info *fi)
+{
+  if (!fi->prev_func.p)
+    {
+      fi->prev_func.p = 1;
+      fi->prev_func.addr = get_pc_function_start (frame_pc_unwind (fi));
+    }
+  return fi->prev_func.addr;
+}
+
+CORE_ADDR
+get_frame_func (struct frame_info *fi)
+{
+  return frame_func_unwind (fi->next);
 }
 
 static int
@@ -505,12 +518,10 @@ create_sentinel_frame (struct regcache *regcache)
   /* Link this frame back to itself.  The frame is self referential
      (the unwound PC is the same as the pc), so make it so.  */
   frame->next = frame;
-  /* Always unwind the PC as part of creating this frame.  This
-     ensures that the frame's PC points at something valid.  */
-  /* FIXME: cagney/2003-01-10: Problem here.  Unwinding a sentinel
-     frame's PC may require information such as the frame's thread's
-     stop reason.  Is it possible to get to that?  */
-  frame->pc = frame_pc_unwind (frame);
+  /* Make the sentinel frame's ID valid, but invalid.  That way all
+     comparisons with it should fail.  */
+  frame->id_p = 1;
+  frame->id = null_frame_id;
   return frame;
 }
 
@@ -640,7 +651,7 @@ select_frame (struct frame_info *fi)
      source language of this frame, and switch to it if desired.  */
   if (fi)
     {
-      s = find_pc_symtab (fi->pc);
+      s = find_pc_symtab (get_frame_pc (fi));
       if (s
          && s->language != current_language->la_language
          && s->language != language_unknown
@@ -755,8 +766,7 @@ legacy_saved_regs_this_id (struct frame_info *next_frame,
         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.  */
-      (*id).base = read_fp ();
-      (*id).pc = read_pc ();
+      (*id) = frame_id_build (read_fp (), read_pc ());
       return;
     }
 
@@ -800,7 +810,7 @@ legacy_saved_regs_this_id (struct frame_info *next_frame,
       gdb_assert (DEPRECATED_FRAME_CHAIN_P ());
       base = DEPRECATED_FRAME_CHAIN (next_frame);
 
-      if (!frame_chain_valid (base, next_frame))
+      if (!legacy_frame_chain_valid (base, next_frame))
        return;
     }
   if (base == 0)
@@ -809,11 +819,12 @@ legacy_saved_regs_this_id (struct frame_info *next_frame,
   /* FIXME: cagney/2002-06-08: This should probably return the frame's
      function and not the PC (a.k.a. resume address).  */
   pc = frame_pc_unwind (next_frame);
-  id->pc = pc;
-  id->base = base;
+  (*id) = frame_id_build (base, pc);
 }
        
 const struct frame_unwind legacy_saved_regs_unwinder = {
+  /* Not really.  It gets overridden by legacy_get_prev_frame.  */
+  UNKNOWN_FRAME,
   legacy_saved_regs_this_id,
   legacy_saved_regs_prev_register
 };
@@ -954,17 +965,22 @@ create_new_frame (CORE_ADDR addr, CORE_ADDR pc)
 
   fi = frame_obstack_zalloc (sizeof (struct frame_info));
 
-  fi->frame = addr;
-  fi->pc = pc;
   fi->next = create_sentinel_frame (current_regcache);
-  fi->type = frame_type_from_pc (pc);
+
+  /* Select/initialize both the unwind function and the frame's type
+     based on the PC.  */
+  fi->unwind = frame_unwind_find_by_pc (current_gdbarch, pc);
+  if (fi->unwind->type != UNKNOWN_FRAME)
+    fi->type = fi->unwind->type;
+  else
+    fi->type = frame_type_from_pc (pc);
+
+  deprecated_update_frame_base_hack (fi, addr);
+  deprecated_update_frame_pc_hack (fi, pc);
 
   if (DEPRECATED_INIT_EXTRA_FRAME_INFO_P ())
     DEPRECATED_INIT_EXTRA_FRAME_INFO (0, fi);
 
-  /* Select/initialize an unwind function.  */
-  fi->unwind = frame_unwind_find_by_pc (current_gdbarch, fi->pc);
-
   return fi;
 }
 
@@ -1019,10 +1035,7 @@ 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.
+  /* Allocate the new frame.
 
      There is no reason to worry about memory leaks, should the
      remainder of the function fail.  The allocated memory will be
@@ -1032,6 +1045,17 @@ legacy_get_prev_frame (struct frame_info *this_frame)
   prev = FRAME_OBSTACK_ZALLOC (struct frame_info);
   prev->level = this_frame->level + 1;
 
+  /* Do not completly wire it in to the frame chain.  Some (bad) code
+     in INIT_FRAME_EXTRA_INFO tries to look along frame->prev to pull
+     some fancy tricks (of course such code is, by definition,
+     recursive).
+  
+     On the other hand, methods, such as get_frame_pc() and
+     get_frame_base() rely on being able to walk along the frame
+     chain.  Make certain that at least they work by providing that
+     link.  Of course things manipulating prev can't go back.  */
+  prev->next = this_frame;
+
   /* 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
@@ -1042,7 +1066,7 @@ legacy_get_prev_frame (struct frame_info *this_frame)
      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;
+  prev->type = UNKNOWN_FRAME;
 
   /* A legacy frame's ID is always computed here.  Mark it as valid.  */
   prev->id_p = 1;
@@ -1068,8 +1092,8 @@ legacy_get_prev_frame (struct frame_info *this_frame)
         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)
+      deprecated_update_frame_pc_hack (prev, frame_pc_unwind (this_frame));
+      if (get_frame_pc (prev) == 0)
        {
          /* The allocated PREV_FRAME will be reclaimed when the frame
             obstack is next purged.  */
@@ -1078,10 +1102,15 @@ legacy_get_prev_frame (struct frame_info *this_frame)
                                "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);
+      /* Set the unwind functions based on that identified PC.  Ditto
+         for the "type" but strongly prefer the unwinder's frame type.  */
+      prev->unwind = frame_unwind_find_by_pc (current_gdbarch,
+                                             get_frame_pc (prev));
+      if (prev->unwind->type == UNKNOWN_FRAME)
+       prev->type = frame_type_from_pc (get_frame_pc (prev));
+      else
+       prev->type = prev->unwind->type;
 
       /* Find the prev's frame's ID.  */
       if (prev->type == DUMMY_FRAME
@@ -1112,8 +1141,7 @@ legacy_get_prev_frame (struct frame_info *this_frame)
             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 ();
+         prev->id = frame_id_build (read_fp (), read_pc ());
        }
 
       /* Check that the unwound ID is valid.  */
@@ -1134,15 +1162,8 @@ legacy_get_prev_frame (struct frame_info *this_frame)
         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
@@ -1209,7 +1230,7 @@ legacy_get_prev_frame (struct frame_info *this_frame)
       gdb_assert (DEPRECATED_FRAME_CHAIN_P ());
       address = DEPRECATED_FRAME_CHAIN (this_frame);
 
-      if (!frame_chain_valid (address, this_frame))
+      if (!legacy_frame_chain_valid (address, this_frame))
        return 0;
     }
   if (address == 0)
@@ -1217,8 +1238,7 @@ legacy_get_prev_frame (struct frame_info *this_frame)
 
   /* Link in the already allocated prev frame.  */
   this_frame->prev = prev;
-  prev->next = this_frame;
-  prev->frame = address;
+  deprecated_update_frame_base_hack (prev, address);
 
   /* This change should not be needed, FIXME!  We should determine
      whether any targets *need* DEPRECATED_INIT_FRAME_PC to happen
@@ -1294,7 +1314,9 @@ legacy_get_prev_frame (struct frame_info *this_frame)
      that PC value.  */
 
   if (DEPRECATED_INIT_FRAME_PC_FIRST_P ())
-    prev->pc = (DEPRECATED_INIT_FRAME_PC_FIRST (fromleaf, prev));
+    deprecated_update_frame_pc_hack (prev,
+                                    DEPRECATED_INIT_FRAME_PC_FIRST (fromleaf,
+                                                                    prev));
 
   if (DEPRECATED_INIT_EXTRA_FRAME_INFO_P ())
     DEPRECATED_INIT_EXTRA_FRAME_INFO (fromleaf, prev);
@@ -1303,15 +1325,17 @@ legacy_get_prev_frame (struct frame_info *this_frame)
      FRAME_SAVED_PC may use that queue to figure out its value (see
      tm-sparc.h).  We want the pc saved in the inferior frame. */
   if (DEPRECATED_INIT_FRAME_PC_P ())
-    prev->pc = DEPRECATED_INIT_FRAME_PC (fromleaf, prev);
+    deprecated_update_frame_pc_hack (prev,
+                                    DEPRECATED_INIT_FRAME_PC (fromleaf,
+                                                              prev));
 
   /* If ->frame and ->pc are unchanged, we are in the process of
      getting ourselves into an infinite backtrace.  Some architectures
      check this in DEPRECATED_FRAME_CHAIN or thereabouts, but it seems
      like there is no reason this can't be an architecture-independent
      check.  */
-  if (prev->frame == this_frame->frame
-      && prev->pc == this_frame->pc)
+  if (get_frame_base (prev) == get_frame_base (this_frame)
+      && get_frame_pc (prev) == get_frame_pc (this_frame))
     {
       this_frame->prev = NULL;
       obstack_free (&frame_cache_obstack, prev);
@@ -1322,7 +1346,16 @@ legacy_get_prev_frame (struct frame_info *this_frame)
      (and probably other architectural information).  The PC lets you
      check things like the debug info at that point (dwarf2cfi?) and
      use that to decide how the frame should be unwound.  */
-  prev->unwind = frame_unwind_find_by_pc (current_gdbarch, prev->pc);
+  prev->unwind = frame_unwind_find_by_pc (current_gdbarch,
+                                         get_frame_pc (prev));
+
+  /* If the unwinder provides a frame type, use it.  Otherwize
+     continue on to that heuristic mess.  */
+  if (prev->unwind->type != UNKNOWN_FRAME)
+    {
+      prev->type = prev->unwind->type;
+      return prev;
+    }
 
   /* NOTE: cagney/2002-11-18: The code segments, found in
      create_new_frame and get_prev_frame(), that initializes the
@@ -1334,8 +1367,8 @@ legacy_get_prev_frame (struct frame_info *this_frame)
      before the INIT function has been called.  */
   if (DEPRECATED_USE_GENERIC_DUMMY_FRAMES
       && (DEPRECATED_PC_IN_CALL_DUMMY_P ()
-         ? DEPRECATED_PC_IN_CALL_DUMMY (prev->pc, 0, 0)
-         : pc_in_dummy_frame (prev->pc)))
+         ? DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (prev), 0, 0)
+         : pc_in_dummy_frame (get_frame_pc (prev))))
     prev->type = DUMMY_FRAME;
   else
     {
@@ -1346,8 +1379,8 @@ legacy_get_prev_frame (struct frame_info *this_frame)
         Unforunatly, its the INIT code that sets the PC (Hmm, catch
         22).  */
       char *name;
-      find_pc_partial_function (prev->pc, &name, NULL, NULL);
-      if (PC_IN_SIGTRAMP (prev->pc, name))
+      find_pc_partial_function (get_frame_pc (prev), &name, NULL, NULL);
+      if (PC_IN_SIGTRAMP (get_frame_pc (prev), name))
        prev->type = SIGTRAMP_FRAME;
       /* FIXME: cagney/2002-11-11: Leave prev->type alone.  Some
          architectures are forcing the frame's type in INIT so we
@@ -1550,8 +1583,7 @@ get_prev_frame (struct frame_info *this_frame)
      because (well ignoring the PPC) a dummy frame can be located
      using THIS_FRAME's frame ID.  */
 
-  prev_frame->pc = frame_pc_unwind (this_frame);
-  if (prev_frame->pc == 0)
+  if (frame_pc_unwind (this_frame) == 0)
     {
       /* The allocated PREV_FRAME will be reclaimed when the frame
         obstack is next purged.  */
@@ -1560,11 +1592,21 @@ get_prev_frame (struct frame_info *this_frame)
                            "Outermost frame - unwound PC zero\n");
       return NULL;
     }
-  prev_frame->type = frame_type_from_pc (prev_frame->pc);
 
   /* Set the unwind functions based on that identified PC.  */
   prev_frame->unwind = frame_unwind_find_by_pc (current_gdbarch,
-                                               prev_frame->pc);
+                                               frame_pc_unwind (this_frame));
+
+  /* FIXME: cagney/2003-04-02: Rather than storing the frame's type in
+     the frame, the unwinder's type should be returned directly.
+     Unfortunatly, legacy code, called by legacy_get_prev_frame,
+     explicitly set the frames type using the method
+     deprecated_set_frame_type().  */
+  gdb_assert (prev_frame->unwind->type != UNKNOWN_FRAME);
+  prev_frame->type = prev_frame->unwind->type;
+
+  /* Can the frame's type and unwinder be computed on demand?  That
+     would make a frame's creation really really lite!  */
 
   /* The prev's frame's ID is computed by demand in get_frame_id().  */
 
@@ -1590,7 +1632,8 @@ get_prev_frame (struct frame_info *this_frame)
 CORE_ADDR
 get_frame_pc (struct frame_info *frame)
 {
-  return frame->pc;
+  gdb_assert (frame->next != NULL);
+  return frame_pc_unwind (frame->next);
 }
 
 static int
@@ -1613,7 +1656,7 @@ pc_notcurrent (struct frame_info *frame)
 void
 find_frame_sal (struct frame_info *frame, struct symtab_and_line *sal)
 {
-  (*sal) = find_pc_line (frame->pc, pc_notcurrent (frame));
+  (*sal) = find_pc_line (get_frame_pc (frame), pc_notcurrent (frame));
 }
 
 /* Per "frame.h", return the ``address'' of the frame.  Code should
@@ -1621,13 +1664,59 @@ find_frame_sal (struct frame_info *frame, struct symtab_and_line *sal)
 CORE_ADDR
 get_frame_base (struct frame_info *fi)
 {
-  if (!fi->id_p)
-    {
-      /* HACK: Force the ID code to (indirectly) initialize the
-         ->frame pointer.  */
-      get_frame_id (fi);
-    }
-  return fi->frame;
+  return get_frame_id (fi).base;
+}
+
+/* High-level offsets into the frame.  Used by the debug info.  */
+
+CORE_ADDR
+get_frame_base_address (struct frame_info *fi)
+{
+  if (get_frame_type (fi) != NORMAL_FRAME)
+    return 0;
+  if (fi->base == NULL)
+    fi->base = frame_base_find_by_pc (current_gdbarch, get_frame_pc (fi));
+  /* 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);
+}
+
+CORE_ADDR
+get_frame_locals_address (struct frame_info *fi)
+{
+  void **cache;
+  if (get_frame_type (fi) != NORMAL_FRAME)
+    return 0;
+  /* If there isn't a frame address method, find it.  */
+  if (fi->base == NULL)
+    fi->base = frame_base_find_by_pc (current_gdbarch, get_frame_pc (fi));
+  /* 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);
+}
+
+CORE_ADDR
+get_frame_args_address (struct frame_info *fi)
+{
+  void **cache;
+  if (get_frame_type (fi) != NORMAL_FRAME)
+    return 0;
+  /* If there isn't a frame address method, find it.  */
+  if (fi->base == NULL)
+    fi->base = frame_base_find_by_pc (current_gdbarch, get_frame_pc (fi));
+  /* 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);
 }
 
 /* Level of the selected frame: 0 for innermost, 1 for its caller, ...
@@ -1650,7 +1739,10 @@ get_frame_type (struct frame_info *frame)
   if (!DEPRECATED_USE_GENERIC_DUMMY_FRAMES
       && deprecated_frame_in_dummy (frame))
     return DUMMY_FRAME;
-  return frame->type;
+  if (frame->type == UNKNOWN_FRAME)
+    return NORMAL_FRAME;
+  else
+    return frame->type;
 }
 
 void
@@ -1660,34 +1752,6 @@ deprecated_set_frame_type (struct frame_info *frame, enum frame_type type)
   frame->type = type;
 }
 
-#ifdef FRAME_FIND_SAVED_REGS
-/* XXX - deprecated.  This is a compatibility function for targets
-   that do not yet implement DEPRECATED_FRAME_INIT_SAVED_REGS.  */
-/* Find the addresses in which registers are saved in FRAME.  */
-
-void
-deprecated_get_frame_saved_regs (struct frame_info *frame,
-                                struct frame_saved_regs *saved_regs_addr)
-{
-  if (frame->saved_regs == NULL)
-    {
-      frame->saved_regs = (CORE_ADDR *)
-       frame_obstack_zalloc (SIZEOF_FRAME_SAVED_REGS);
-    }
-  if (saved_regs_addr == NULL)
-    {
-      struct frame_saved_regs saved_regs;
-      FRAME_FIND_SAVED_REGS (frame, saved_regs);
-      memcpy (frame->saved_regs, &saved_regs, SIZEOF_FRAME_SAVED_REGS);
-    }
-  else
-    {
-      FRAME_FIND_SAVED_REGS (frame, *saved_regs_addr);
-      memcpy (frame->saved_regs, saved_regs_addr, SIZEOF_FRAME_SAVED_REGS);
-    }
-}
-#endif
-
 struct frame_extra_info *
 get_frame_extra_info (struct frame_info *fi)
 {
@@ -1704,8 +1768,6 @@ frame_extra_info_zalloc (struct frame_info *fi, long size)
 void
 deprecated_update_frame_pc_hack (struct frame_info *frame, CORE_ADDR pc)
 {
-  /* See comment in "frame.h".  */
-  frame->pc = pc;
   /* NOTE: cagney/2003-03-11: Some architectures (e.g., Arm) are
      maintaining a locally allocated frame object.  Since such frame's
      are not in the frame chain, it isn't possible to assume that the
@@ -1715,8 +1777,8 @@ deprecated_update_frame_pc_hack (struct frame_info *frame, CORE_ADDR pc)
       /* While we're at it, update this frame's cached PC value, found
         in the next frame.  Oh for the day when "struct frame_info"
         is opaque and this hack on hack can just go away.  */
-      frame->next->pc_unwind_cache = pc;
-      frame->next->pc_unwind_cache_p = 1;
+      frame->next->prev_pc.value = pc;
+      frame->next->prev_pc.p = 1;
     }
 }
 
@@ -1724,7 +1786,7 @@ void
 deprecated_update_frame_base_hack (struct frame_info *frame, CORE_ADDR base)
 {
   /* See comment in "frame.h".  */
-  frame->frame = base;
+  frame->id.base = base;
 }
 
 void
This page took 0.036774 seconds and 4 git commands to generate.