oops - omitted from previous delta
[deliverable/binutils-gdb.git] / gdb / frame.c
index cd0c3792c3a2e05c916aa778a12437bde9672fb7..fd2b3eac198e7a150e7ad5f6a54860b4264c8f8b 100644 (file)
@@ -1,7 +1,7 @@
 /* Cache and manage frames for GDB, the GNU debugger.
 
    Copyright 1986, 1987, 1989, 1991, 1994, 1995, 1996, 1998, 2000,
-   2001, 2002 Free Software Foundation, Inc.
+   2001, 2002, 2003 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #include "builtin-regs.h"
 #include "gdb_obstack.h"
 #include "dummy-frame.h"
+#include "sentinel-frame.h"
 #include "gdbcore.h"
 #include "annotate.h"
+#include "language.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "command.h"
+#include "gdbcmd.h"
 
-/* Return a frame uniq ID that can be used to, later re-find the
+/* Flag to control debugging.  */
+
+static int frame_debug;
+
+/* Flag to indicate whether backtraces should stop at main.  */
+
+static int backtrace_below_main;
+
+/* Return a frame uniq ID that can be used to, later, re-find the
    frame.  */
 
-void
-get_frame_id (struct frame_info *fi, struct frame_id *id)
+struct frame_id
+get_frame_id (struct frame_info *fi)
 {
   if (fi == NULL)
     {
-      id->base = 0;
-      id->pc = 0;
+      return null_frame_id;
     }
-  else
+  if (!fi->id_p)
     {
-      id->base = FRAME_FP (fi);
-      id->pc = fi->pc;
+      gdb_assert (!legacy_frame_p (current_gdbarch));
+      /* 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.  */
+      fi->frame = fi->id.base;
     }
+  return frame_id_build (fi->frame, get_frame_pc (fi));
+}
+
+const struct frame_id null_frame_id; /* All zeros.  */
+
+struct frame_id
+frame_id_build (CORE_ADDR base, CORE_ADDR func_or_pc)
+{
+  struct frame_id id;
+  id.base = base;
+  id.pc = func_or_pc;
+  return id;
+}
+
+int
+frame_id_p (struct frame_id l)
+{
+  /* The .func can be NULL but the .base cannot.  */
+  return (l.base != 0);
+}
+
+int
+frame_id_eq (struct frame_id l, struct frame_id r)
+{
+  /* If .base is different, the frames are different.  */
+  if (l.base != r.base)
+    return 0;
+  /* Add a test to check that the frame ID's are for the same function
+     here.  */
+  return 1;
+}
+
+int
+frame_id_inner (struct frame_id l, struct frame_id r)
+{
+  /* Only return non-zero when strictly inner than.  Note that, per
+     comment in "frame.h", there is some fuzz here.  Frameless
+     functions are not strictly inner than (same .base but different
+     .func).  */
+  return INNER_THAN (l.base, r.base);
 }
 
 struct frame_info *
@@ -59,40 +117,142 @@ frame_find_by_id (struct frame_id id)
 
   /* ZERO denotes the null frame, let the caller decide what to do
      about it.  Should it instead return get_current_frame()?  */
-  if (id.base == 0 && id.pc == 0)
+  if (!frame_id_p (id))
     return NULL;
 
   for (frame = get_current_frame ();
        frame != NULL;
        frame = get_prev_frame (frame))
     {
-      if (INNER_THAN (FRAME_FP (frame), id.base))
-       /* ``inner/current < frame < id.base''.  Keep looking along
-           the frame chain.  */
-       continue;
-      if (INNER_THAN (id.base, FRAME_FP (frame)))
-       /* ``inner/current < id.base < frame''.  Oops, gone past it.
-           Just give up.  */
+      struct frame_id this = get_frame_id (frame);
+      if (frame_id_eq (id, this))
+       /* An exact match.  */
+       return frame;
+      if (frame_id_inner (id, this))
+       /* Gone to far.  */
        return NULL;
-      /* FIXME: cagney/2002-04-21: This isn't sufficient.  It should
-        use id.pc to check that the two frames belong to the same
-        function.  Otherwise we'll do things like match dummy frames
-        or mis-match frameless functions.  However, until someone
-        notices, stick with the existing behavour.  */
-      return frame;
+      /* Either, we're not yet gone far enough out along the frame
+         chain (inner(this,id), or we're comparing frameless functions
+         (same .base, different .func, no test available).  Struggle
+         on until we've definitly gone to far.  */
     }
   return NULL;
 }
 
 CORE_ADDR
-frame_pc_unwind (struct frame_info *frame)
+frame_pc_unwind (struct frame_info *this_frame)
+{
+  if (!this_frame->pc_unwind_cache_p)
+    {
+      CORE_ADDR pc;
+      if (gdbarch_unwind_pc_p (current_gdbarch))
+       {
+         /* The right way.  The `pure' way.  The one true way.  This
+            method depends solely on the register-unwind code to
+            determine the value of registers in THIS frame, and hence
+            the value of this frame's PC (resume address).  A typical
+            implementation is no more than:
+          
+            frame_unwind_register (this_frame, ISA_PC_REGNUM, buf);
+            return extract_address (buf, size of ISA_PC_REGNUM);
+
+            Note: this method is very heavily dependent on a correct
+            register-unwind implementation, it pays to fix that
+            method first; this method is frame type agnostic, since
+            it only deals with register values, it works with any
+            frame.  This is all in stark contrast to the old
+            FRAME_SAVED_PC which would try to directly handle all the
+            different ways that a PC could be unwound.  */
+         pc = gdbarch_unwind_pc (current_gdbarch, this_frame);
+       }
+      else if (this_frame->level < 0)
+       {
+         /* FIXME: cagney/2003-03-06: Old code and and a sentinel
+             frame.  Do like was always done.  Fetch the PC's value
+             direct from the global registers array (via read_pc).
+             This assumes that this frame belongs to the current
+             global register cache.  The assumption is dangerous.  */
+         pc = read_pc ();
+       }
+      else if (DEPRECATED_FRAME_SAVED_PC_P ())
+       {
+         /* FIXME: cagney/2003-03-06: Old code, but not a sentinel
+             frame.  Do like was always done.  Note that this method,
+             unlike unwind_pc(), tries to handle all the different
+             frame cases directly.  It fails.  */
+         pc = DEPRECATED_FRAME_SAVED_PC (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;
+    }
+  return this_frame->pc_unwind_cache;
+}
+
+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
+do_frame_unwind_register (void *src, int regnum, void *buf)
+{
+  frame_unwind_register (src, regnum, buf);
+  return 1;
+}
+
+void
+frame_pop (struct frame_info *this_frame)
 {
-  if (!frame->pc_unwind_cache_p)
+  struct regcache *scratch_regcache;
+  struct cleanup *cleanups;
+
+  if (DEPRECATED_POP_FRAME_P ())
+    {
+      /* A legacy architecture that has implemented a custom pop
+        function.  All new architectures should instead be using the
+        generic code below.  */
+      DEPRECATED_POP_FRAME;
+    }
+  else
     {
-      frame->pc_unwind_cache = frame->pc_unwind (frame, &frame->unwind_cache);
-      frame->pc_unwind_cache_p = 1;
+      /* Make a copy of all the register values unwound from this
+        frame.  Save them in a scratch buffer so that there isn't a
+        race betweening trying to extract the old values from the
+        current_regcache while, at the same time writing new values
+        into that same cache.  */
+      struct regcache *scratch = regcache_xmalloc (current_gdbarch);
+      struct cleanup *cleanups = make_cleanup_regcache_xfree (scratch);
+      regcache_save (scratch, do_frame_unwind_register, this_frame);
+      /* FIXME: cagney/2003-03-16: It should be possible to tell the
+         target's register cache that it is about to be hit with a
+         burst register transfer and that the sequence of register
+         writes should be batched.  The pair target_prepare_to_store()
+         and target_store_registers() kind of suggest this
+         functionality.  Unfortunatly, they don't implement it.  Their
+         lack of a formal definition can lead to targets writing back
+         bogus values (arguably a bug in the target code mind).  */
+      /* Now copy those saved registers into the current regcache.
+         Here, regcache_cpy() calls regcache_restore().  */
+      regcache_cpy (current_regcache, scratch);
+      do_cleanups (cleanups);
     }
-  return frame->pc_unwind_cache;
+  /* We've made right mess of GDB's local state, just discard
+     everything.  */
+  flush_cached_frames ();
 }
 
 void
@@ -110,33 +270,18 @@ frame_register_unwind (struct frame_info *frame, int regnum,
   gdb_assert (realnump != NULL);
   /* gdb_assert (bufferp != NULL); */
 
-  /* NOTE: cagney/2002-04-14: It would be nice if, instead of a
-     special case, there was always an inner frame dedicated to the
-     hardware registers.  Unfortunatly, there is too much unwind code
-     around that looks up/down the frame chain while making the
-     assumption that each frame level is using the same unwind code.  */
+  /* NOTE: cagney/2002-11-27: A program trying to unwind a NULL frame
+     is broken.  There is always a frame.  If there, for some reason,
+     isn't, there is some pretty busted code as it should have
+     detected the problem before calling here.  */
+  gdb_assert (frame != NULL);
 
-  if (frame == NULL)
-    {
-      /* We're in the inner-most frame, get the value direct from the
-        register cache.  */
-      *optimizedp = 0;
-      *lvalp = lval_register;
-      /* ULGH!  Code uses the offset into the raw register byte array
-         as a way of identifying a register.  */
-      *addrp = REGISTER_BYTE (regnum);
-      /* Should this code test ``register_cached (regnum) < 0'' and do
-         something like set realnum to -1 when the register isn't
-         available?  */
-      *realnump = regnum;
-      if (bufferp)
-       deprecated_read_register_gen (regnum, bufferp);
-      return;
-    }
+  /* Ask this frame to unwind its register.  See comment in
+     "frame-unwind.h" for why NEXT frame and this unwind cace are
+     passed in.  */
+  frame->unwind->prev_register (frame->next, &frame->prologue_cache, regnum,
+                               optimizedp, lvalp, addrp, realnump, bufferp);
 
-  /* Ask this frame to unwind its register.  */
-  frame->register_unwind (frame, &frame->unwind_cache, regnum,
-                         optimizedp, lvalp, addrp, realnump, bufferp);
 }
 
 void
@@ -155,9 +300,10 @@ frame_register (struct frame_info *frame, int regnum,
   /* Ulgh!  Old code that, for lval_register, sets ADDRP to the offset
      of the register in the register cache.  It should instead return
      the REGNUM corresponding to that register.  Translate the .  */
-  if (GET_SAVED_REGISTER_P ())
+  if (DEPRECATED_GET_SAVED_REGISTER_P ())
     {
-      GET_SAVED_REGISTER (bufferp, optimizedp, addrp, frame, regnum, lvalp);
+      DEPRECATED_GET_SAVED_REGISTER (bufferp, optimizedp, addrp, frame,
+                                    regnum, lvalp);
       /* Compute the REALNUM if the caller wants it.  */
       if (*lvalp == lval_register)
        {
@@ -178,38 +324,30 @@ frame_register (struct frame_info *frame, int regnum,
       return;
     }
 
-  /* Reached the the bottom (youngest, inner most) of the frame chain
-     (youngest, inner most) frame, go direct to the hardware register
-     cache (do not pass go, do not try to cache the value, ...).  The
-     unwound value would have been cached in frame->next but that
-     doesn't exist.  This doesn't matter as the hardware register
-     cache is stopping any unnecessary accesses to the target.  */
-
-  /* NOTE: cagney/2002-04-14: It would be nice if, instead of a
-     special case, there was always an inner frame dedicated to the
-     hardware registers.  Unfortunatly, there is too much unwind code
-     around that looks up/down the frame chain while making the
-     assumption that each frame level is using the same unwind code.  */
-
-  if (frame == NULL)
-    frame_register_unwind (NULL, regnum, optimizedp, lvalp, addrp, realnump,
-                          bufferp);
-  else
-    frame_register_unwind (frame->next, regnum, optimizedp, lvalp, addrp,
-                          realnump, bufferp);
+  /* Obtain the register value by unwinding the register from the next
+     (more inner frame).  */
+  gdb_assert (frame != NULL && frame->next != NULL);
+  frame_register_unwind (frame->next, regnum, optimizedp, lvalp, addrp,
+                        realnump, bufferp);
 }
 
 void
-frame_unwind_signed_register (struct frame_info *frame, int regnum,
-                             LONGEST *val)
+frame_unwind_register (struct frame_info *frame, int regnum, void *buf)
 {
   int optimized;
   CORE_ADDR addr;
   int realnum;
   enum lval_type lval;
-  void *buf = alloca (MAX_REGISTER_RAW_SIZE);
   frame_register_unwind (frame, regnum, &optimized, &lval, &addr,
                         &realnum, buf);
+}
+
+void
+frame_unwind_signed_register (struct frame_info *frame, int regnum,
+                             LONGEST *val)
+{
+  void *buf = alloca (MAX_REGISTER_RAW_SIZE);
+  frame_unwind_register (frame, regnum, buf);
   (*val) = extract_signed_integer (buf, REGISTER_VIRTUAL_SIZE (regnum));
 }
 
@@ -217,16 +355,18 @@ void
 frame_unwind_unsigned_register (struct frame_info *frame, int regnum,
                                ULONGEST *val)
 {
-  int optimized;
-  CORE_ADDR addr;
-  int realnum;
-  enum lval_type lval;
   void *buf = alloca (MAX_REGISTER_RAW_SIZE);
-  frame_register_unwind (frame, regnum, &optimized, &lval, &addr,
-                        &realnum, buf);
+  frame_unwind_register (frame, regnum, buf);
   (*val) = extract_unsigned_integer (buf, REGISTER_VIRTUAL_SIZE (regnum));
 }
 
+void
+frame_read_register (struct frame_info *frame, int regnum, void *buf)
+{
+  gdb_assert (frame != NULL && frame->next != NULL);
+  frame_unwind_register (frame->next, regnum, buf);
+}
+
 void
 frame_read_unsigned_register (struct frame_info *frame, int regnum,
                              ULONGEST *val)
@@ -248,20 +388,20 @@ frame_read_unsigned_register (struct frame_info *frame, int regnum,
      tests like ``if get_next_frame() == NULL'' and instead just rely
      on recursive frame calls (like the below code) when manipulating
      a frame chain.  */
-  gdb_assert (frame != NULL);
-  frame_unwind_unsigned_register (get_next_frame (frame), regnum, val);
+  gdb_assert (frame != NULL && frame->next != NULL);
+  frame_unwind_unsigned_register (frame->next, regnum, val);
 }
 
 void
 frame_read_signed_register (struct frame_info *frame, int regnum,
                            LONGEST *val)
 {
-  /* See note in frame_read_unsigned_register().  */
-  gdb_assert (frame != NULL);
-  frame_unwind_signed_register (get_next_frame (frame), regnum, val);
+  /* See note above in frame_read_unsigned_register().  */
+  gdb_assert (frame != NULL && frame->next != NULL);
+  frame_unwind_signed_register (frame->next, regnum, val);
 }
 
-static void
+void
 generic_unwind_get_saved_register (char *raw_buffer,
                                   int *optimizedp,
                                   CORE_ADDR *addrp,
@@ -286,42 +426,9 @@ generic_unwind_get_saved_register (char *raw_buffer,
   if (addrp == NULL)
     addrp = &addrx;
 
-  /* Reached the the bottom (youngest, inner most) of the frame chain
-     (youngest, inner most) frame, go direct to the hardware register
-     cache (do not pass go, do not try to cache the value, ...).  The
-     unwound value would have been cached in frame->next but that
-     doesn't exist.  This doesn't matter as the hardware register
-     cache is stopping any unnecessary accesses to the target.  */
-
-  /* NOTE: cagney/2002-04-14: It would be nice if, instead of a
-     special case, there was always an inner frame dedicated to the
-     hardware registers.  Unfortunatly, there is too much unwind code
-     around that looks up/down the frame chain while making the
-     assumption that each frame level is using the same unwind code.  */
-
-  if (frame == NULL)
-    frame_register_unwind (NULL, regnum, optimizedp, lvalp, addrp, &realnumx,
-                          raw_buffer);
-  else
-    frame_register_unwind (frame->next, regnum, optimizedp, lvalp, addrp,
-                          &realnumx, raw_buffer);
-}
-
-void
-get_saved_register (char *raw_buffer,
-                   int *optimized,
-                   CORE_ADDR *addrp,
-                   struct frame_info *frame,
-                   int regnum,
-                   enum lval_type *lval)
-{
-  if (GET_SAVED_REGISTER_P ())
-    {
-      GET_SAVED_REGISTER (raw_buffer, optimized, addrp, frame, regnum, lval);
-      return;
-    }
-  generic_unwind_get_saved_register (raw_buffer, optimized, addrp, frame,
-                                    regnum, lval);
+  gdb_assert (frame != NULL && frame->next != NULL);
+  frame_register_unwind (frame->next, regnum, optimizedp, lvalp, addrp,
+                        &realnumx, raw_buffer);
 }
 
 /* frame_register_read ()
@@ -363,6 +470,9 @@ frame_map_name_to_regnum (const char *name, int len)
 {
   int i;
 
+  if (len < 0)
+    len = strlen (name);
+
   /* Search register name space. */
   for (i = 0; i < NUM_REGS + NUM_PSEUDO_REGS; i++)
     if (REGISTER_NAME (i) && len == strlen (REGISTER_NAME (i))
@@ -394,6 +504,38 @@ frame_map_regnum_to_name (int regnum)
   return builtin_reg_map_regnum_to_name (regnum);
 }
 
+/* Create a sentinel frame.  */
+
+struct frame_info *
+create_sentinel_frame (struct regcache *regcache)
+{
+  struct frame_info *frame = FRAME_OBSTACK_ZALLOC (struct frame_info);
+  frame->type = NORMAL_FRAME;
+  frame->level = -1;
+  /* Explicitly initialize the sentinel frame's cache.  Provide it
+     with the underlying regcache.  In the future additional
+     information, such as the frame's thread will be added.  */
+  frame->prologue_cache = sentinel_frame_cache (regcache);
+  /* For the moment there is only one sentinel frame implementation.  */
+  frame->unwind = sentinel_frame_unwind;
+  /* 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?  */
+  /* FIXME: cagney/2003-04-04: Once ->pc is eliminated, this
+     assignment can go away.  */
+  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;
+}
+
 /* Info about the innermost stack frame (contents of FP register) */
 
 static struct frame_info *current_frame;
@@ -405,39 +547,130 @@ static struct frame_info *current_frame;
 static struct obstack frame_cache_obstack;
 
 void *
-frame_obstack_alloc (unsigned long size)
+frame_obstack_zalloc (unsigned long size)
 {
-  return obstack_alloc (&frame_cache_obstack, size);
+  void *data = obstack_alloc (&frame_cache_obstack, size);
+  memset (data, 0, size);
+  return data;
 }
 
-void
+CORE_ADDR *
 frame_saved_regs_zalloc (struct frame_info *fi)
 {
   fi->saved_regs = (CORE_ADDR *)
-    frame_obstack_alloc (SIZEOF_FRAME_SAVED_REGS);
-  memset (fi->saved_regs, 0, SIZEOF_FRAME_SAVED_REGS);
+    frame_obstack_zalloc (SIZEOF_FRAME_SAVED_REGS);
+  return fi->saved_regs;
 }
 
+CORE_ADDR *
+get_frame_saved_regs (struct frame_info *fi)
+{
+  return fi->saved_regs;
+}
 
-/* Return the innermost (currently executing) stack frame.  */
+/* Return the innermost (currently executing) stack frame.  This is
+   split into two functions.  The function unwind_to_current_frame()
+   is wrapped in catch exceptions so that, even when the unwind of the
+   sentinel frame fails, the function still returns a stack frame.  */
+
+static int
+unwind_to_current_frame (struct ui_out *ui_out, void *args)
+{
+  struct frame_info *frame = get_prev_frame (args);
+  /* A sentinel frame can fail to unwind, eg, because it's PC value
+     lands in somewhere like start.  */
+  if (frame == NULL)
+    return 1;
+  current_frame = frame;
+  return 0;
+}
 
 struct frame_info *
 get_current_frame (void)
 {
+  /* First check, and report, the lack of registers.  Having GDB
+     report "No stack!" or "No memory" when the target doesn't even
+     have registers is very confusing.  Besides, "printcmd.exp"
+     explicitly checks that ``print $pc'' with no registers prints "No
+     registers".  */
+  if (!target_has_registers)
+    error ("No registers.");
+  if (!target_has_stack)
+    error ("No stack.");
+  if (!target_has_memory)
+    error ("No memory.");
   if (current_frame == NULL)
     {
-      if (target_has_stack)
-       current_frame = create_new_frame (read_fp (), read_pc ());
-      else
-       error ("No stack.");
+      struct frame_info *sentinel_frame =
+       create_sentinel_frame (current_regcache);
+      if (catch_exceptions (uiout, unwind_to_current_frame, sentinel_frame,
+                           NULL, RETURN_MASK_ERROR) != 0)
+       {
+         /* Oops! Fake a current frame?  Is this useful?  It has a PC
+             of zero, for instance.  */
+         current_frame = sentinel_frame;
+       }
     }
   return current_frame;
 }
 
+/* The "selected" stack frame is used by default for local and arg
+   access.  May be zero, for no selected frame.  */
+
+struct frame_info *deprecated_selected_frame;
+
+/* Return the selected frame.  Always non-null (unless there isn't an
+   inferior sufficient for creating a frame) in which case an error is
+   thrown.  */
+
+struct frame_info *
+get_selected_frame (void)
+{
+  if (deprecated_selected_frame == NULL)
+    /* Hey!  Don't trust this.  It should really be re-finding the
+       last selected frame of the currently selected thread.  This,
+       though, is better than nothing.  */
+    select_frame (get_current_frame ());
+  /* There is always a frame.  */
+  gdb_assert (deprecated_selected_frame != NULL);
+  return deprecated_selected_frame;
+}
+
+/* Select frame FI (or NULL - to invalidate the current frame).  */
+
 void
-set_current_frame (struct frame_info *frame)
+select_frame (struct frame_info *fi)
 {
-  current_frame = frame;
+  register struct symtab *s;
+
+  deprecated_selected_frame = fi;
+  /* NOTE: cagney/2002-05-04: FI can be NULL.  This occures when the
+     frame is being invalidated.  */
+  if (selected_frame_level_changed_hook)
+    selected_frame_level_changed_hook (frame_relative_level (fi));
+
+  /* FIXME: kseitz/2002-08-28: It would be nice to call
+     selected_frame_level_changed_event right here, but due to limitations
+     in the current interfaces, we would end up flooding UIs with events
+     because select_frame is used extensively internally.
+
+     Once we have frame-parameterized frame (and frame-related) commands,
+     the event notification can be moved here, since this function will only
+     be called when the users selected frame is being changed. */
+
+  /* Ensure that symbols for this frame are read in.  Also, determine the
+     source language of this frame, and switch to it if desired.  */
+  if (fi)
+    {
+      s = find_pc_symtab (get_frame_pc (fi));
+      if (s
+         && s->language != current_language->la_language
+         && s->language != language_unknown
+         && language_mode == language_mode_auto)
+       {
+         set_language (s->language);
+       }
+    }
 }
 
 /* Return the register saved in the simplistic ``saved_regs'' cache.
@@ -445,26 +678,32 @@ set_current_frame (struct frame_info *frame)
    most frame.  */
 
 static void
-frame_saved_regs_register_unwind (struct frame_info *frame, void **cache,
-                                 int regnum, int *optimizedp,
-                                 enum lval_type *lvalp, CORE_ADDR *addrp,
-                                 int *realnump, void *bufferp)
+legacy_saved_regs_prev_register (struct frame_info *next_frame,
+                                void **this_prologue_cache,
+                                int regnum, int *optimizedp,
+                                enum lval_type *lvalp, CORE_ADDR *addrp,
+                                int *realnump, void *bufferp)
 {
-  /* There is always a frame at this point.  And THIS is the frame
-     we're interested in.  */
+  /* HACK: New code is passed the next frame and this cache.
+     Unfortunatly, old code expects this frame.  Since this is a
+     backward compatibility hack, cheat by walking one level along the
+     prologue chain to the frame the old code expects.
+
+     Do not try this at home.  Professional driver, closed course.  */
+  struct frame_info *frame = next_frame->prev;
   gdb_assert (frame != NULL);
-  /* If we're using generic dummy frames, we'd better not be in a call
-     dummy.  (generic_call_dummy_register_unwind ought to have been called
-     instead.)  */
-  gdb_assert (!(USE_GENERIC_DUMMY_FRAMES
-                && PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame)));
+
+  /* Only (older) architectures that implement the
+     DEPRECATED_FRAME_INIT_SAVED_REGS method should be using this
+     function.  */
+  gdb_assert (DEPRECATED_FRAME_INIT_SAVED_REGS_P ());
 
   /* Load the saved_regs register cache.  */
-  if (frame->saved_regs == NULL)
-    FRAME_INIT_SAVED_REGS (frame);
+  if (get_frame_saved_regs (frame) == NULL)
+    DEPRECATED_FRAME_INIT_SAVED_REGS (frame);
 
-  if (frame->saved_regs != NULL
-      && frame->saved_regs[regnum] != 0)
+  if (get_frame_saved_regs (frame) != NULL
+      && get_frame_saved_regs (frame)[regnum] != 0)
     {
       if (regnum == SP_REGNUM)
        {
@@ -475,7 +714,7 @@ frame_saved_regs_register_unwind (struct frame_info *frame, void **cache,
          *realnump = -1;
          if (bufferp != NULL)
            store_address (bufferp, REGISTER_RAW_SIZE (regnum),
-                          frame->saved_regs[regnum]);
+                          get_frame_saved_regs (frame)[regnum]);
        }
       else
        {
@@ -483,33 +722,32 @@ frame_saved_regs_register_unwind (struct frame_info *frame, void **cache,
              a local copy of its value.  */
          *optimizedp = 0;
          *lvalp = lval_memory;
-         *addrp = frame->saved_regs[regnum];
+         *addrp = get_frame_saved_regs (frame)[regnum];
          *realnump = -1;
          if (bufferp != NULL)
            {
 #if 1
              /* Save each register value, as it is read in, in a
                  frame based cache.  */
-             void **regs = (*cache);
+             void **regs = (*this_prologue_cache);
              if (regs == NULL)
                {
                  int sizeof_cache = ((NUM_REGS + NUM_PSEUDO_REGS)
                                      * sizeof (void *));
-                 regs = frame_obstack_alloc (sizeof_cache);
-                 memset (regs, 0, sizeof_cache);
-                 (*cache) = regs;
+                 regs = frame_obstack_zalloc (sizeof_cache);
+                 (*this_prologue_cache) = regs;
                }
              if (regs[regnum] == NULL)
                {
                  regs[regnum]
-                   = frame_obstack_alloc (REGISTER_RAW_SIZE (regnum));
-                 read_memory (frame->saved_regs[regnum], regs[regnum],
+                   = frame_obstack_zalloc (REGISTER_RAW_SIZE (regnum));
+                 read_memory (get_frame_saved_regs (frame)[regnum], regs[regnum],
                               REGISTER_RAW_SIZE (regnum));
                }
              memcpy (bufferp, regs[regnum], REGISTER_RAW_SIZE (regnum));
 #else
              /* Read the value in from memory.  */
-             read_memory (frame->saved_regs[regnum], bufferp,
+             read_memory (get_frame_saved_regs (frame)[regnum], bufferp,
                           REGISTER_RAW_SIZE (regnum));
 #endif
            }
@@ -517,33 +755,96 @@ frame_saved_regs_register_unwind (struct frame_info *frame, void **cache,
       return;
     }
 
-  /* No luck, assume this and the next frame have the same register
-     value.  If a value is needed, pass the request on down the chain;
-     otherwise just return an indication that the value is in the same
-     register as the next frame.  */
-  if (bufferp == NULL)
+  /* No luck.  Assume this and the next frame have the same register
+     value.  Pass the unwind request down the frame chain to the next
+     frame.  Hopefully that frame will find the register's location.  */
+  frame_register_unwind (next_frame, regnum, optimizedp, lvalp, addrp,
+                        realnump, bufferp);
+}
+
+static void
+legacy_saved_regs_this_id (struct frame_info *next_frame,
+                          void **this_prologue_cache,
+                          struct frame_id *id)
+{
+  int fromleaf;
+  CORE_ADDR base;
+  CORE_ADDR pc;
+
+  if (frame_relative_level (next_frame) < 0)
     {
-      *optimizedp = 0;
-      *lvalp = lval_register;
-      *addrp = 0;
-      *realnump = regnum;
+      /* FIXME: cagney/2003-03-14: We've got the extra special case of
+        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) = frame_id_build (read_fp (), read_pc ());
+      return;
     }
+
+  /* Start out by assuming it's NULL.  */
+  (*id) = null_frame_id;
+
+  if (frame_relative_level (next_frame) <= 0)
+    /* 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.  */
+    base = get_frame_base (next_frame);
   else
     {
-      frame_register_unwind (frame->next, regnum, optimizedp, lvalp, addrp,
-                            realnump, bufferp);
+      /* 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.  */
+      gdb_assert (DEPRECATED_FRAME_CHAIN_P ());
+      base = DEPRECATED_FRAME_CHAIN (next_frame);
+
+      if (!legacy_frame_chain_valid (base, next_frame))
+       return;
     }
-}
+  if (base == 0)
+    return;
 
-static CORE_ADDR
-frame_saved_regs_pc_unwind (struct frame_info *frame, void **cache)
-{
-  return FRAME_SAVED_PC (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) = frame_id_build (base, pc);
 }
        
-/* Function: get_saved_register
+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
+};
+const struct frame_unwind *legacy_saved_regs_unwind = &legacy_saved_regs_unwinder;
+
+
+/* Function: deprecated_generic_get_saved_register
    Find register number REGNUM relative to FRAME and put its (raw,
-   target format) contents in *RAW_BUFFER.  
+   target format) contents in *RAW_BUFFER.
 
    Set *OPTIMIZED if the variable was optimized out (and thus can't be
    fetched).  Note that this is never set to anything other than zero
@@ -559,10 +860,6 @@ frame_saved_regs_pc_unwind (struct frame_info *frame, void **cache)
    offset into the registers array.  If the value is stored in a dummy
    frame, set *ADDRP to zero.
 
-   To use this implementation, define a function called
-   "get_saved_register" in your target code, which simply passes all
-   of its arguments to this function.
-
    The argument RAW_BUFFER must point to aligned memory.  */
 
 void
@@ -574,6 +871,8 @@ deprecated_generic_get_saved_register (char *raw_buffer, int *optimized,
   if (!target_has_registers)
     error ("No registers.");
 
+  gdb_assert (DEPRECATED_FRAME_INIT_SAVED_REGS_P ());
+
   /* Normal systems don't optimize out things with register numbers.  */
   if (optimized != NULL)
     *optimized = 0;
@@ -586,44 +885,50 @@ deprecated_generic_get_saved_register (char *raw_buffer, int *optimized,
      the current frame itself: otherwise, we would be getting the
      previous frame's registers which were saved by the current frame.  */
 
-  while (frame && ((frame = frame->next) != NULL))
+  if (frame != NULL)
     {
-      if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame))
+      for (frame = get_next_frame (frame);
+          frame_relative_level (frame) >= 0;
+          frame = get_next_frame (frame))
        {
-         if (lval)             /* found it in a CALL_DUMMY frame */
-           *lval = not_lval;
-         if (raw_buffer)
-           /* FIXME: cagney/2002-06-26: This should be via the
-              gdbarch_register_read() method so that it, on the fly,
-              constructs either a raw or pseudo register from the raw
-              register cache.  */
-           regcache_raw_read (generic_find_dummy_frame (frame->pc,
-                                                        frame->frame),
-                              regnum, raw_buffer);
-         return;
-       }
-
-      FRAME_INIT_SAVED_REGS (frame);
-      if (frame->saved_regs != NULL
-         && frame->saved_regs[regnum] != 0)
-       {
-         if (lval)             /* found it saved on the stack */
-           *lval = lval_memory;
-         if (regnum == SP_REGNUM)
+         if (get_frame_type (frame) == DUMMY_FRAME)
            {
-             if (raw_buffer)   /* SP register treated specially */
-               store_address (raw_buffer, REGISTER_RAW_SIZE (regnum),
-                              frame->saved_regs[regnum]);
+             if (lval)         /* found it in a CALL_DUMMY frame */
+               *lval = not_lval;
+             if (raw_buffer)
+               /* FIXME: cagney/2002-06-26: This should be via the
+                  gdbarch_register_read() method so that it, on the
+                  fly, constructs either a raw or pseudo register
+                  from the raw register cache.  */
+               regcache_raw_read
+                 (generic_find_dummy_frame (get_frame_pc (frame),
+                                            get_frame_base (frame)),
+                  regnum, raw_buffer);
+             return;
            }
-         else
+
+         DEPRECATED_FRAME_INIT_SAVED_REGS (frame);
+         if (get_frame_saved_regs (frame) != NULL
+             && get_frame_saved_regs (frame)[regnum] != 0)
            {
-             if (addrp)        /* any other register */
-               *addrp = frame->saved_regs[regnum];
-             if (raw_buffer)
-               read_memory (frame->saved_regs[regnum], raw_buffer,
-                            REGISTER_RAW_SIZE (regnum));
+             if (lval)         /* found it saved on the stack */
+               *lval = lval_memory;
+             if (regnum == SP_REGNUM)
+               {
+                 if (raw_buffer)       /* SP register treated specially */
+                   store_address (raw_buffer, REGISTER_RAW_SIZE (regnum),
+                                  get_frame_saved_regs (frame)[regnum]);
+               }
+             else
+               {
+                 if (addrp)    /* any other register */
+                   *addrp = get_frame_saved_regs (frame)[regnum];
+                 if (raw_buffer)
+                   read_memory (get_frame_saved_regs (frame)[regnum], raw_buffer,
+                                REGISTER_RAW_SIZE (regnum));
+               }
+             return;
            }
-         return;
        }
     }
 
@@ -638,33 +943,26 @@ deprecated_generic_get_saved_register (char *raw_buffer, int *optimized,
     deprecated_read_register_gen (regnum, raw_buffer);
 }
 
-/* Using the PC, select a mechanism for unwinding a frame returning
-   the previous frame.  The register unwind function should, on
-   demand, initialize the ->context object.  */
+/* Determine the frame's type based on its PC.  */
 
-static void
-set_unwind_by_pc (CORE_ADDR pc, CORE_ADDR fp,
-                 frame_register_unwind_ftype **unwind_register,
-                 frame_pc_unwind_ftype **unwind_pc)
+static enum frame_type
+frame_type_from_pc (CORE_ADDR pc)
 {
-  if (!USE_GENERIC_DUMMY_FRAMES)
-    {
-      /* Still need to set this to something.  The ``info frame'' code
-        calls this function to find out where the saved registers are.
-        Hopefully this is robust enough to stop any core dumps and
-        return vaguely correct values..  */
-      *unwind_register = frame_saved_regs_register_unwind;
-      *unwind_pc = frame_saved_regs_pc_unwind;
-    }
-  else if (PC_IN_CALL_DUMMY (pc, fp, fp))
-    {
-      *unwind_register = dummy_frame_register_unwind;
-      *unwind_pc = dummy_frame_pc_unwind;
-    }
+  /* FIXME: cagney/2002-11-24: Can't yet directly call
+     pc_in_dummy_frame() as some architectures don't set
+     PC_IN_CALL_DUMMY() to generic_pc_in_call_dummy() (remember the
+     latter is implemented by simply calling pc_in_dummy_frame).  */
+  if (DEPRECATED_USE_GENERIC_DUMMY_FRAMES
+      && DEPRECATED_PC_IN_CALL_DUMMY (pc, 0, 0))
+    return DUMMY_FRAME;
   else
     {
-      *unwind_register = frame_saved_regs_register_unwind;
-      *unwind_pc = frame_saved_regs_pc_unwind;
+      char *name;
+      find_pc_partial_function (pc, &name, NULL, NULL);
+      if (PC_IN_SIGTRAMP (pc, name))
+       return SIGTRAMP_FRAME;
+      else
+       return NORMAL_FRAME;
     }
 }
 
@@ -675,37 +973,39 @@ struct frame_info *
 create_new_frame (CORE_ADDR addr, CORE_ADDR pc)
 {
   struct frame_info *fi;
-  char *name;
 
-  fi = (struct frame_info *)
-    obstack_alloc (&frame_cache_obstack,
-                  sizeof (struct frame_info));
+  fi = frame_obstack_zalloc (sizeof (struct frame_info));
 
-  /* Zero all fields by default.  */
-  memset (fi, 0, sizeof (struct frame_info));
+  fi->next = create_sentinel_frame (current_regcache);
 
-  fi->frame = addr;
-  fi->pc = pc;
-  find_pc_partial_function (pc, &name, (CORE_ADDR *) NULL, (CORE_ADDR *) NULL);
-  fi->signal_handler_caller = PC_IN_SIGTRAMP (fi->pc, name);
+  /* Select/initialize both the unwind function and the frame's type
+     based on the PC.  */
+  fi->unwind = frame_unwind_find_by_pc (current_gdbarch, fi->pc);
+  if (fi->unwind->type != UNKNOWN_FRAME)
+    fi->type = fi->unwind->type;
+  else
+    fi->type = frame_type_from_pc (pc);
 
-  if (INIT_EXTRA_FRAME_INFO_P ())
-    INIT_EXTRA_FRAME_INFO (0, fi);
+  deprecated_update_frame_base_hack (fi, addr);
+  deprecated_update_frame_pc_hack (fi, pc);
 
-  /* Select/initialize an unwind function.  */
-  set_unwind_by_pc (fi->pc, fi->frame, &fi->register_unwind,
-                   &fi->pc_unwind);
+  if (DEPRECATED_INIT_EXTRA_FRAME_INFO_P ())
+    DEPRECATED_INIT_EXTRA_FRAME_INFO (0, fi);
 
   return fi;
 }
 
-/* Return the frame that FRAME calls (NULL if FRAME is the innermost
-   frame).  */
+/* Return the frame that THIS_FRAME calls (NULL if THIS_FRAME is the
+   innermost frame).  Be careful to not fall off the bottom of the
+   frame chain and onto the sentinel frame.  */
 
 struct frame_info *
-get_next_frame (struct frame_info *frame)
+get_next_frame (struct frame_info *this_frame)
 {
-  return frame->next;
+  if (this_frame->level > 0)
+    return this_frame->next;
+  else
+    return NULL;
 }
 
 /* Flush the entire frame cache.  */
@@ -736,44 +1036,169 @@ reinit_frame_cache (void)
     }
 }
 
-/* Return a structure containing various interesting information
-   about the frame that called NEXT_FRAME.  Returns NULL
-   if there is no such frame.  */
+/* Create the previous frame using the deprecated methods
+   INIT_EXTRA_INFO, INIT_FRAME_PC and INIT_FRAME_PC_FIRST.  */
 
-struct frame_info *
-get_prev_frame (struct frame_info *next_frame)
+static struct frame_info *
+legacy_get_prev_frame (struct frame_info *this_frame)
 {
   CORE_ADDR address = 0;
   struct frame_info *prev;
   int fromleaf;
-  char *name;
 
-  /* Return the inner-most frame, when the caller passes in NULL.  */
-  /* NOTE: cagney/2002-11-09: Not sure how this would happen.  The
-     caller should have previously obtained a valid frame using
-     get_selected_frame() and then called this code - only possibility
-     I can think of is code behaving badly.  */
-  if (next_frame == NULL)
+  /* 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
+     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;
+
+  /* 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
+     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 = UNKNOWN_FRAME;
+
+  /* A legacy frame's ID is always computed here.  Mark it as valid.  */
+  prev->id_p = 1;
+
+  /* Handle sentinel frame unwind as a special case.  */
+  if (this_frame->level < 0)
     {
-      /* NOTE: cagney/2002-11-09: There was a code segment here that
-        would error out when CURRENT_FRAME was NULL.  The comment
-        that went with it made the claim ...
+      /* 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, DEPRECATED_FRAME_SAVED_PC) and
+        DEPRECATED_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.  */
+      
+      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.  */
+         if (frame_debug)
+           fprintf_unfiltered (gdb_stdlog,
+                               "Outermost frame - unwound PC zero\n");
+         return NULL;
+       }
 
-        ``This screws value_of_variable, which just wants a nice
-        clean NULL return from block_innermost_frame if there are no
-        frames.  I don't think I've ever seen this message happen
-        otherwise.  And returning NULL here is a perfectly legitimate
-        thing to do.''
+      /* 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, prev->pc);
+      if (prev->unwind->type == UNKNOWN_FRAME)
+       prev->type = frame_type_from_pc (prev->pc);
+      else
+       prev->type = prev->unwind->type;
 
-         Per the above, this code shouldn't even be called with a NULL
-         NEXT_FRAME.  */
-      return current_frame;
+      /* 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 call_function_by_hand(), 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 = frame_id_build (read_fp (), 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.  */
+      /* FIXME: cagney/2003-04-04: Once ->frame is eliminated, this
+         assignment can go.  */
+      prev->frame = prev->id.base;
+
+      /* Link it in.  */
+      this_frame->prev = prev;
+
+      /* 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;
     }
 
-  /* Only try to do the unwind once.  */
-  if (next_frame->prev_p)
-    return next_frame->prev;
-  next_frame->prev_p = 1;
+  /* 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);
 
   /* On some machines it is possible to call a function without
      setting up a stack frame for it.  On these machines, we
@@ -782,14 +1207,14 @@ get_prev_frame (struct frame_info *next_frame)
      or isn't leafless.  */
 
   /* Still don't want to worry about this except on the innermost
-     frame.  This macro will set FROMLEAF if NEXT_FRAME is a frameless
+     frame.  This macro will set FROMLEAF if THIS_FRAME is a frameless
      function invocation.  */
-  if (next_frame->next == NULL)
+  if (this_frame->level == 0)
     /* 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);
+    fromleaf = FRAMELESS_FUNCTION_INVOCATION (this_frame);
   else
     fromleaf = 0;
 
@@ -800,7 +1225,7 @@ get_prev_frame (struct frame_info *next_frame)
     /* FIXME: 2002-11-09: There isn't any reason to special case this
        edge condition.  Instead the per-architecture code should hande
        it locally.  */
-    address = FRAME_FP (next_frame);
+    address = get_frame_base (this_frame);
   else
     {
       /* Two macros defined in tm.h specify the machine-dependent
@@ -818,54 +1243,40 @@ get_prev_frame (struct frame_info *next_frame)
          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.  */
-      address = 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 (address, next_frame))
+      gdb_assert (DEPRECATED_FRAME_CHAIN_P ());
+      address = DEPRECATED_FRAME_CHAIN (this_frame);
+
+      if (!legacy_frame_chain_valid (address, this_frame))
        return 0;
     }
   if (address == 0)
     return 0;
 
-  /* Create an initially zero previous frame.  */
-  prev = (struct frame_info *)
-    obstack_alloc (&frame_cache_obstack,
-                  sizeof (struct frame_info));
-  memset (prev, 0, sizeof (struct frame_info));
-
-  /* Link it in.  */
-  next_frame->prev = prev;
-  prev->next = next_frame;
-  prev->frame = address;
-  prev->level = next_frame->level + 1;
+  /* Link in the already allocated prev frame.  */
+  this_frame->prev = prev;
+  deprecated_update_frame_base_hack (prev, address);
 
   /* This change should not be needed, FIXME!  We should determine
-     whether any targets *need* INIT_FRAME_PC to happen after
-     INIT_EXTRA_FRAME_INFO and come up with a simple way to express
-     what goes on here.
+     whether any targets *need* DEPRECATED_INIT_FRAME_PC to happen
+     after DEPRECATED_INIT_EXTRA_FRAME_INFO and come up with a simple
+     way to express what goes on here.
 
-     INIT_EXTRA_FRAME_INFO is called from two places: create_new_frame
-     (where the PC is already set up) and here (where it isn't).
-     INIT_FRAME_PC is only called from here, always after
-     INIT_EXTRA_FRAME_INFO.
+     DEPRECATED_INIT_EXTRA_FRAME_INFO is called from two places:
+     create_new_frame (where the PC is already set up) and here (where
+     it isn't).  DEPRECATED_INIT_FRAME_PC is only called from here,
+     always after DEPRECATED_INIT_EXTRA_FRAME_INFO.
 
-     The catch is the MIPS, where INIT_EXTRA_FRAME_INFO requires the
-     PC value (which hasn't been set yet).  Some other machines appear
-     to require INIT_EXTRA_FRAME_INFO before they can do
-     INIT_FRAME_PC.  Phoo.
+     The catch is the MIPS, where DEPRECATED_INIT_EXTRA_FRAME_INFO
+     requires the PC value (which hasn't been set yet).  Some other
+     machines appear to require DEPRECATED_INIT_EXTRA_FRAME_INFO
+     before they can do DEPRECATED_INIT_FRAME_PC.  Phoo.
 
-     We shouldn't need INIT_FRAME_PC_FIRST to add more complication to
-     an already overcomplicated part of GDB.  gnu@cygnus.com, 15Sep92.
+     We shouldn't need DEPRECATED_INIT_FRAME_PC_FIRST to add more
+     complication to an already overcomplicated part of GDB.
+     gnu@cygnus.com, 15Sep92.
 
-     Assuming that some machines need INIT_FRAME_PC after
-     INIT_EXTRA_FRAME_INFO, one possible scheme:
+     Assuming that some machines need DEPRECATED_INIT_FRAME_PC after
+     DEPRECATED_INIT_EXTRA_FRAME_INFO, one possible scheme:
 
      SETUP_INNERMOST_FRAME(): Default version is just create_new_frame
      (read_fp ()), read_pc ()).  Machines with extra frame info would
@@ -875,18 +1286,20 @@ get_prev_frame (struct frame_info *next_frame)
      create_new_frame would no longer init extra frame info;
      SETUP_ARBITRARY_FRAME would have to do that.
 
-     INIT_PREV_FRAME(fromleaf, prev) Replace INIT_EXTRA_FRAME_INFO and
-     INIT_FRAME_PC.  This should also return a flag saying whether to
-     keep the new frame, or whether to discard it, because on some
-     machines (e.g.  mips) it is really awkward to have
-     FRAME_CHAIN_VALID called *before* INIT_EXTRA_FRAME_INFO (there is
-     no good way to get information deduced in FRAME_CHAIN_VALID into
-     the extra fields of the new frame).  std_frame_pc(fromleaf, prev)
+     INIT_PREV_FRAME(fromleaf, prev) Replace
+     DEPRECATED_INIT_EXTRA_FRAME_INFO and DEPRECATED_INIT_FRAME_PC.
+     This should also return a flag saying whether to keep the new
+     frame, or whether to discard it, because on some machines (e.g.
+     mips) it is really awkward to have DEPRECATED_FRAME_CHAIN_VALID
+     called BEFORE DEPRECATED_INIT_EXTRA_FRAME_INFO (there is no good
+     way to get information deduced in DEPRECATED_FRAME_CHAIN_VALID
+     into the extra fields of the new frame).  std_frame_pc(fromleaf,
+     prev)
 
      This is the default setting for INIT_PREV_FRAME.  It just does
-     what the default INIT_FRAME_PC does.  Some machines will call it
-     from INIT_PREV_FRAME (either at the beginning, the end, or in the
-     middle).  Some machines won't use it.
+     what the default DEPRECATED_INIT_FRAME_PC does.  Some machines
+     will call it from INIT_PREV_FRAME (either at the beginning, the
+     end, or in the middle).  Some machines won't use it.
 
      kingdon@cygnus.com, 13Apr93, 31Jan94, 14Dec94.  */
 
@@ -902,37 +1315,45 @@ get_prev_frame (struct frame_info *next_frame)
      inner most and any other case.
 
      Since there is always a frame to unwind from, there is always
-     somewhere (NEXT_FRAME) to store all the info needed to construct
+     somewhere (THIS_FRAME) to store all the info needed to construct
      a new (previous) frame without having to first create it.  This
      means that the convolution below - needing to carefully order a
      frame's initialization - isn't needed.
 
-     The irony here though, is that FRAME_CHAIN(), at least for a more
-     up-to-date architecture, always calls FRAME_SAVED_PC(), and
-     FRAME_SAVED_PC() computes the PC but without first needing the
-     frame!  Instead of the convolution below, we could have simply
-     called FRAME_SAVED_PC() and been done with it!  Note that
-     FRAME_SAVED_PC() is being superseed by frame_pc_unwind() and that
-     function does have somewhere to cache that PC value.  */
+     The irony here though, is that DEPRECATED_FRAME_CHAIN(), at least
+     for a more up-to-date architecture, always calls
+     FRAME_SAVED_PC(), and FRAME_SAVED_PC() computes the PC but
+     without first needing the frame!  Instead of the convolution
+     below, we could have simply called FRAME_SAVED_PC() and been done
+     with it!  Note that FRAME_SAVED_PC() is being superseed by
+     frame_pc_unwind() and that function does have somewhere to cache
+     that PC value.  */
 
-  INIT_FRAME_PC_FIRST (fromleaf, prev);
+  if (DEPRECATED_INIT_FRAME_PC_FIRST_P ())
+    deprecated_update_frame_pc_hack (prev,
+                                    DEPRECATED_INIT_FRAME_PC_FIRST (fromleaf,
+                                                                    prev));
 
-  if (INIT_EXTRA_FRAME_INFO_P ())
-    INIT_EXTRA_FRAME_INFO (fromleaf, prev);
+  if (DEPRECATED_INIT_EXTRA_FRAME_INFO_P ())
+    DEPRECATED_INIT_EXTRA_FRAME_INFO (fromleaf, prev);
 
   /* This entry is in the frame queue now, which is good since
      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. */
-  INIT_FRAME_PC (fromleaf, prev);
+  if (DEPRECATED_INIT_FRAME_PC_P ())
+    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 FRAME_CHAIN or thereabouts, but it seems like there
-     is no reason this can't be an architecture-independent check.  */
-  if (prev->frame == next_frame->frame
-      && prev->pc == next_frame->pc)
+     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 (get_frame_base (prev) == get_frame_base (this_frame)
+      && get_frame_pc (prev) == get_frame_pc (this_frame))
     {
-      next_frame->prev = NULL;
+      this_frame->prev = NULL;
       obstack_free (&frame_cache_obstack, prev);
       return NULL;
     }
@@ -941,53 +1362,564 @@ get_prev_frame (struct frame_info *next_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.  */
-  set_unwind_by_pc (prev->pc, prev->frame, &prev->register_unwind,
-                   &prev->pc_unwind);
+  prev->unwind = frame_unwind_find_by_pc (current_gdbarch,
+                                         get_frame_pc (prev));
 
-  find_pc_partial_function (prev->pc, &name,
-                           (CORE_ADDR *) NULL, (CORE_ADDR *) NULL);
-  if (PC_IN_SIGTRAMP (prev->pc, name))
-    prev->signal_handler_caller = 1;
+  /* 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
+     frames type is subtly different.  The latter only updates ->type
+     when it encounters a SIGTRAMP_FRAME or DUMMY_FRAME.  This stops
+     get_prev_frame() overriding the frame's type when the INIT code
+     has previously set it.  This is really somewhat bogus.  The
+     initialization, as seen in create_new_frame(), should occur
+     before the INIT function has been called.  */
+  if (DEPRECATED_USE_GENERIC_DUMMY_FRAMES
+      && (DEPRECATED_PC_IN_CALL_DUMMY_P ()
+         ? DEPRECATED_PC_IN_CALL_DUMMY (get_frame_pc (prev), 0, 0)
+         : pc_in_dummy_frame (get_frame_pc (prev))))
+    prev->type = DUMMY_FRAME;
+  else
+    {
+      /* FIXME: cagney/2002-11-10: This should be moved to before the
+        INIT code above so that the INIT code knows what the frame's
+        type is (in fact, for a [generic] dummy-frame, the type can
+        be set and then the entire initialization can be skipped.
+        Unforunatly, its the INIT code that sets the PC (Hmm, catch
+        22).  */
+      char *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
+         don't want to override it here.  Remember, NORMAL_FRAME == 0,
+         so it all works (just :-/).  Once this initialization is
+         moved to the start of this function, all this nastness will
+         go away.  */
+    }
 
   return prev;
 }
 
+/* Return a structure containing various interesting information
+   about the frame that called THIS_FRAME.  Returns NULL
+   if there is no such frame.  */
+
+struct frame_info *
+get_prev_frame (struct frame_info *this_frame)
+{
+  struct frame_info *prev_frame;
+
+  /* Return the inner-most frame, when the caller passes in NULL.  */
+  /* NOTE: cagney/2002-11-09: Not sure how this would happen.  The
+     caller should have previously obtained a valid frame using
+     get_selected_frame() and then called this code - only possibility
+     I can think of is code behaving badly.
+
+     NOTE: cagney/2003-01-10: Talk about code behaving badly.  Check
+     block_innermost_frame().  It does the sequence: frame = NULL;
+     while (1) { frame = get_prev_frame (frame); .... }.  Ulgh!  Why
+     it couldn't be written better, I don't know.
+
+     NOTE: cagney/2003-01-11: I suspect what is happening is
+     block_innermost_frame() is, when the target has no state
+     (registers, memory, ...), still calling this function.  The
+     assumption being that this function will return NULL indicating
+     that a frame isn't possible, rather than checking that the target
+     has state and then calling get_current_frame() and
+     get_prev_frame().  This is a guess mind.  */
+  if (this_frame == NULL)
+    {
+      /* NOTE: cagney/2002-11-09: There was a code segment here that
+        would error out when CURRENT_FRAME was NULL.  The comment
+        that went with it made the claim ...
+
+        ``This screws value_of_variable, which just wants a nice
+        clean NULL return from block_innermost_frame if there are no
+        frames.  I don't think I've ever seen this message happen
+        otherwise.  And returning NULL here is a perfectly legitimate
+        thing to do.''
+
+         Per the above, this code shouldn't even be called with a NULL
+         THIS_FRAME.  */
+      return current_frame;
+    }
+
+  /* There is always a frame.  If this assertion fails, suspect that
+     something should be calling get_selected_frame() or
+     get_current_frame().  */
+  gdb_assert (this_frame != NULL);
+
+  if (this_frame->level >= 0
+      && !backtrace_below_main
+      && inside_main_func (get_frame_pc (this_frame)))
+    /* Don't unwind past main(), bug always unwind the sentinel frame.
+       Note, this is done _before_ the frame has been marked as
+       previously unwound.  That way if the user later decides to
+       allow unwinds past main(), that just happens.  */
+    {
+      if (frame_debug)
+       fprintf_unfiltered (gdb_stdlog,
+                           "Outermost frame - inside main func.\n");
+      return NULL;
+    }
+
+  /* Only try to do the unwind once.  */
+  if (this_frame->prev_p)
+    return this_frame->prev;
+  this_frame->prev_p = 1;
+
+#if 0
+  /* If we're inside the entry file, it isn't valid.  Don't apply this
+     test to a dummy frame - dummy frame PC's typically land in the
+     entry file.  Don't apply this test to the sentinel frame.
+     Sentinel frames should always be allowed to unwind.  */
+  /* NOTE: drow/2002-12-25: should there be a way to disable this
+     check?  It assumes a single small entry file, and the way some
+     debug readers (e.g.  dbxread) figure out which object is the
+     entry file is somewhat hokey.  */
+  /* NOTE: cagney/2003-01-10: If there is a way of disabling this test
+     then it should probably be moved to before the ->prev_p test,
+     above.  */
+  /* NOTE: vinschen/2003-04-01: Disabled.  It turns out that the call to
+     inside_entry_file destroys a meaningful backtrace under some
+     conditions.  E. g. the backtrace tests in the asm-source testcase
+     are broken for some targets.  In this test the functions are all
+     implemented as part of one file and the testcase is not necessarily
+     linked with a start file (depending on the target).  What happens is,
+     that the first frame is printed normaly and following frames are
+     treated as being inside the enttry file then.  This way, only the
+     #0 frame is printed in the backtrace output.  */
+  if (this_frame->type != DUMMY_FRAME && this_frame->level >= 0
+      && inside_entry_file (get_frame_pc (this_frame)))
+    {
+      if (frame_debug)
+       fprintf_unfiltered (gdb_stdlog,
+                           "Outermost frame - inside entry file\n");
+      return NULL;
+    }
+#endif
+
+  /* If we're already inside the entry function for the main objfile,
+     then it isn't valid.  Don't apply this test to a dummy frame -
+     dummy frame PC's typically land in the entry func.  Don't apply
+     this test to the sentinel frame.  Sentinel frames should always
+     be allowed to unwind.  */
+  /* NOTE: cagney/2003-02-25: Don't enable until someone has found
+     hard evidence that this is needed.  */
+  if (0
+      && this_frame->type != DUMMY_FRAME && this_frame->level >= 0
+      && inside_entry_func (get_frame_pc (this_frame)))
+    {
+      if (frame_debug)
+       fprintf_unfiltered (gdb_stdlog,
+                           "Outermost frame - inside entry func\n");
+      return NULL;
+    }
+
+  /* If any of the old frame initialization methods are around, use
+     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)
+       fprintf_unfiltered (gdb_stdlog,
+                           "Outermost frame - legacy_get_prev_frame NULL.\n");
+      return prev_frame;
+    }
+
+  /* Check that this frame's ID was valid.  If it wasn't, don't try to
+     unwind to the prev frame.  Be careful to not apply this test to
+     the sentinel frame.  */
+  if (this_frame->level >= 0 && !frame_id_p (get_frame_id (this_frame)))
+    {
+      if (frame_debug)
+       fprintf_filtered (gdb_stdlog,
+                         "Outermost frame - this ID is NULL\n");
+      return NULL;
+    }
+
+  /* Check that this frame's ID isn't inner to (younger, below, next)
+     the next frame.  This happens when frame unwind goes backwards.
+     Since the sentinel frame isn't valid, don't apply this if this
+     frame is entier the inner-most or sentinel frame.  */
+  if (this_frame->level > 0
+      && frame_id_inner (get_frame_id (this_frame),
+                        get_frame_id (this_frame->next)))
+    error ("This frame inner-to next frame (corrupt stack?)");
+
+  /* Check that this and the next frame are different.  If they are
+     not, there is most likely a stack cycle.  As with the inner-than
+     test, avoid the inner-most and sentinel frames.  */
+  /* FIXME: cagney/2003-03-17: Can't yet enable this this check. The
+     frame_id_eq() method doesn't yet use function addresses when
+     comparing frame IDs.  */
+  if (0
+      && this_frame->level > 0
+      && frame_id_eq (get_frame_id (this_frame),
+                     get_frame_id (this_frame->next)))
+    error ("This frame identical to next frame (corrupt stack?)");
+
+  /* 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 above will stop repeated memory
+     allocation calls.  */
+  prev_frame = FRAME_OBSTACK_ZALLOC (struct frame_info);
+  prev_frame->level = this_frame->level + 1;
+
+  /* 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
+     DEPRECATED_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.  */
+
+  /* FIXME: cagney/2003-04-04: Once ->pc is eliminated, this
+     assignment can go away.  */
+  prev_frame->pc = frame_pc_unwind (this_frame);
+  if (prev_frame->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;
+    }
+
+  /* Set the unwind functions based on that identified PC.  */
+  prev_frame->unwind = frame_unwind_find_by_pc (current_gdbarch,
+                                               prev_frame->pc);
+
+  /* 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().  */
+
+  /* The unwound frame ID is validate at the start of this function,
+     as part of the logic to decide if that frame should be further
+     unwound, and not here while the prev frame is being created.
+     Doing this makes it possible for the user to examine a frame that
+     has an invalid frame ID.
+
+     The very old VAX frame_args_address_correct() method noted: [...]
+     For the sake of argument, suppose that the stack is somewhat
+     trashed (which is one reason that "info frame" exists).  So,
+     return 0 (indicating we don't know the address of the arglist) if
+     we don't know what frame this frame calls.  */
+
+  /* Link it in.  */
+  this_frame->prev = prev_frame;
+  prev_frame->next = this_frame;
+
+  return prev_frame;
+}
+
 CORE_ADDR
 get_frame_pc (struct frame_info *frame)
 {
   return frame->pc;
 }
 
-#ifdef FRAME_FIND_SAVED_REGS
-/* XXX - deprecated.  This is a compatibility function for targets
-   that do not yet implement FRAME_INIT_SAVED_REGS.  */
-/* Find the addresses in which registers are saved in FRAME.  */
+static int
+pc_notcurrent (struct frame_info *frame)
+{
+  /* If FRAME is not the innermost frame, that normally means that
+     FRAME->pc points at the return instruction (which is *after* the
+     call instruction), and we want to get the line containing the
+     call (because the call is where the user thinks the program is).
+     However, if the next frame is either a SIGTRAMP_FRAME or a
+     DUMMY_FRAME, then the next frame will contain a saved interrupt
+     PC and such a PC indicates the current (rather than next)
+     instruction/line, consequently, for such cases, want to get the
+     line containing fi->pc.  */
+  struct frame_info *next = get_next_frame (frame);
+  int notcurrent = (next != NULL && get_frame_type (next) == NORMAL_FRAME);
+  return notcurrent;
+}
+
+void
+find_frame_sal (struct frame_info *frame, struct symtab_and_line *sal)
+{
+  (*sal) = find_pc_line (get_frame_pc (frame), pc_notcurrent (frame));
+}
+
+/* Per "frame.h", return the ``address'' of the frame.  Code should
+   really be using get_frame_id().  */
+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;
+}
+
+/* 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, ...
+   or -1 for a NULL frame.  */
+
+int
+frame_relative_level (struct frame_info *fi)
+{
+  if (fi == NULL)
+    return -1;
+  else
+    return fi->level;
+}
+
+enum frame_type
+get_frame_type (struct frame_info *frame)
+{
+  /* Some targets still don't use [generic] dummy frames.  Catch them
+     here.  */
+  if (!DEPRECATED_USE_GENERIC_DUMMY_FRAMES
+      && deprecated_frame_in_dummy (frame))
+    return DUMMY_FRAME;
+  if (frame->type == UNKNOWN_FRAME)
+    return NORMAL_FRAME;
+  else
+    return frame->type;
+}
+
+void
+deprecated_set_frame_type (struct frame_info *frame, enum frame_type type)
+{
+  /* Arrrg!  See comment in "frame.h".  */
+  frame->type = type;
+}
+
+struct frame_extra_info *
+get_frame_extra_info (struct frame_info *fi)
+{
+  return fi->extra_info;
+}
+
+struct frame_extra_info *
+frame_extra_info_zalloc (struct frame_info *fi, long size)
+{
+  fi->extra_info = frame_obstack_zalloc (size);
+  return fi->extra_info;
+}
 
 void
-get_frame_saved_regs (struct frame_info *frame,
-                     struct frame_saved_regs *saved_regs_addr)
+deprecated_update_frame_pc_hack (struct frame_info *frame, CORE_ADDR pc)
 {
-  if (frame->saved_regs == NULL)
+  /* 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
+     frame has a next.  Sigh.  */
+  if (frame->next != NULL)
     {
-      frame->saved_regs = (CORE_ADDR *)
-       frame_obstack_alloc (SIZEOF_FRAME_SAVED_REGS);
+      /* 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;
     }
-  if (saved_regs_addr == NULL)
+}
+
+void
+deprecated_update_frame_base_hack (struct frame_info *frame, CORE_ADDR base)
+{
+  /* See comment in "frame.h".  */
+  frame->frame = base;
+}
+
+void
+deprecated_set_frame_saved_regs_hack (struct frame_info *frame,
+                                     CORE_ADDR *saved_regs)
+{
+  frame->saved_regs = saved_regs;
+}
+
+void
+deprecated_set_frame_extra_info_hack (struct frame_info *frame,
+                                     struct frame_extra_info *extra_info)
+{
+  frame->extra_info = extra_info;
+}
+
+void
+deprecated_set_frame_next_hack (struct frame_info *fi,
+                               struct frame_info *next)
+{
+  fi->next = next;
+}
+
+void
+deprecated_set_frame_prev_hack (struct frame_info *fi,
+                               struct frame_info *prev)
+{
+  fi->prev = prev;
+}
+
+struct context *
+deprecated_get_frame_context (struct frame_info *fi)
+{
+  return fi->context;
+}
+
+void
+deprecated_set_frame_context (struct frame_info *fi,
+                             struct context *context)
+{
+  fi->context = context;
+}
+
+struct frame_info *
+deprecated_frame_xmalloc (void)
+{
+  struct frame_info *frame = XMALLOC (struct frame_info);
+  memset (frame, 0, sizeof (struct frame_info));
+  return frame;
+}
+
+struct frame_info *
+deprecated_frame_xmalloc_with_cleanup (long sizeof_saved_regs,
+                                      long sizeof_extra_info)
+{
+  struct frame_info *frame = deprecated_frame_xmalloc ();
+  make_cleanup (xfree, frame);
+  if (sizeof_saved_regs > 0)
     {
-      struct frame_saved_regs saved_regs;
-      FRAME_FIND_SAVED_REGS (frame, saved_regs);
-      memcpy (frame->saved_regs, &saved_regs, SIZEOF_FRAME_SAVED_REGS);
+      frame->saved_regs = xcalloc (1, sizeof_saved_regs);
+      make_cleanup (xfree, frame->saved_regs);
     }
-  else
+  if (sizeof_extra_info > 0)
     {
-      FRAME_FIND_SAVED_REGS (frame, *saved_regs_addr);
-      memcpy (frame->saved_regs, saved_regs_addr, SIZEOF_FRAME_SAVED_REGS);
+      frame->extra_info = xcalloc (1, sizeof_extra_info);
+      make_cleanup (xfree, frame->extra_info);
     }
+  return frame;
+}
+
+int
+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 ()
+         || DEPRECATED_FRAME_CHAIN_P ()
+         || !gdbarch_unwind_dummy_id_p (current_gdbarch)
+         || !SAVE_DUMMY_FRAME_TOS_P ());
 }
-#endif
 
 void
 _initialize_frame (void)
 {
   obstack_init (&frame_cache_obstack);
+
+  /* FIXME: cagney/2003-01-19: This command needs a rename.  Suggest
+     `set backtrace {past,beyond,...}-main'.  Also suggest adding `set
+     backtrace ...-start' to control backtraces past start.  The
+     problem with `below' is that it stops the `up' command.  */
+
+  add_setshow_boolean_cmd ("backtrace-below-main", class_obscure,
+                          &backtrace_below_main, "\
+Set whether backtraces should continue past \"main\".\n\
+Normally the caller of \"main\" is not of interest, so GDB will terminate\n\
+the backtrace at \"main\".  Set this variable if you need to see the rest\n\
+of the stack trace.", "\
+Show whether backtraces should continue past \"main\".\n\
+Normally the caller of \"main\" is not of interest, so GDB will terminate\n\
+the backtrace at \"main\".  Set this variable if you need to see the rest\n\
+of the stack trace.",
+                          NULL, NULL, &setlist, &showlist);
+
+
+  /* Debug this files internals. */
+  add_show_from_set (add_set_cmd ("frame", class_maintenance, var_zinteger,
+                                 &frame_debug, "Set frame debugging.\n\
+When non-zero, frame specific internal debugging is enabled.", &setdebuglist),
+                    &showdebuglist);
 }
This page took 0.047459 seconds and 4 git commands to generate.