2005-02-15 Andrew Cagney <cagney@gnu.org>
[deliverable/binutils-gdb.git] / gdb / frame.c
index b1107efa8e5ad46c00e320fd46ea283048dccbcf..7a8076bbceae7d8f4ca82e9f663affc49a75dbb1 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, 2003 Free Software Foundation, Inc.
+   2001, 2002, 2003, 2004 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -28,7 +28,7 @@
 #include "regcache.h"
 #include "gdb_assert.h"
 #include "gdb_string.h"
-#include "builtin-regs.h"
+#include "user-regs.h"
 #include "gdb_obstack.h"
 #include "dummy-frame.h"
 #include "sentinel-frame.h"
 #include "frame-base.h"
 #include "command.h"
 #include "gdbcmd.h"
+#include "observer.h"
+#include "objfiles.h"
+#include "exceptions.h"
+
+static struct frame_info *get_prev_frame_1 (struct frame_info *this_frame);
 
 /* We keep a cache of stack frames, each of which is a "struct
    frame_info".  The innermost one gets allocated (in
@@ -57,43 +62,16 @@ struct frame_info
      increases.  This is a cached value.  It could just as easily be
      computed by counting back from the selected frame to the inner
      most frame.  */
-  /* NOTE: cagney/2002-04-05: Perhaphs a level of ``-1'' should be
+  /* NOTE: cagney/2002-04-05: Perhaps a level of ``-1'' should be
      reserved to indicate a bogus frame - one that has been created
      just to keep GDB happy (GDB always needs a frame).  For the
      moment leave this as speculation.  */
   int level;
 
-  /* The frame's type.  */
-  /* FIXME: cagney/2003-04-02: Should instead be returning
-     ->unwind->type.  Unfortunatly, legacy code is still explicitly
-     setting the type using the method deprecated_set_frame_type.
-     Eliminate that method and this field can be eliminated.  */
-  enum frame_type type;
-
-  /* For each register, address of where it was saved on entry to the
-     frame, or zero if it was not saved on entry to this frame.  This
-     includes special registers such as pc and fp saved in special
-     ways in the stack frame.  The SP_REGNUM is even more special, the
-     address here is the sp for the previous frame, not the address
-     where the sp was saved.  */
-  /* Allocated by frame_saved_regs_zalloc () which is called /
-     initialized by DEPRECATED_FRAME_INIT_SAVED_REGS(). */
-  CORE_ADDR *saved_regs;       /*NUM_REGS + NUM_PSEUDO_REGS*/
-
-  /* Anything extra for this structure that may have been defined in
-     the machine dependent files. */
-  /* Allocated by frame_extra_info_zalloc () which is called /
-     initialized by DEPRECATED_INIT_EXTRA_FRAME_INFO */
-  struct frame_extra_info *extra_info;
-
-  /* If dwarf2 unwind frame informations is used, this structure holds
-     all related unwind data.  */
-  struct context *context;
-
   /* The frame's low-level unwinder and corresponding cache.  The
      low-level unwinder is responsible for unwinding register values
      for the previous frame.  The low-level unwind methods are
-     selected based on the presence, or otherwize, of register unwind
+     selected based on the presence, or otherwise, of register unwind
      information such as CFI.  */
   void *prologue_cache;
   const struct frame_unwind *unwind;
@@ -135,16 +113,31 @@ struct frame_info
 
 static int frame_debug;
 
-/* Flag to indicate whether backtraces should stop at main.  */
+/* Flag to indicate whether backtraces should stop at main et.al.  */
 
-static int backtrace_below_main;
+static int backtrace_past_main;
+static int backtrace_past_entry;
+static unsigned int backtrace_limit = UINT_MAX;
+
+static void
+fprint_field (struct ui_file *file, const char *name, int p, CORE_ADDR addr)
+{
+  if (p)
+    fprintf_unfiltered (file, "%s=0x%s", name, paddr_nz (addr));
+  else
+    fprintf_unfiltered (file, "!%s", name);
+}
 
 void
 fprint_frame_id (struct ui_file *file, struct frame_id id)
 {
-  fprintf_unfiltered (file, "{stack=0x%s,code=0x%s}",
-                     paddr_nz (id.stack_addr),
-                     paddr_nz (id.code_addr));
+  fprintf_unfiltered (file, "{");
+  fprint_field (file, "stack", id.stack_addr_p, id.stack_addr);
+  fprintf_unfiltered (file, ",");
+  fprint_field (file, "code", id.code_addr_p, id.code_addr);
+  fprintf_unfiltered (file, ",");
+  fprint_field (file, "special", id.special_addr_p, id.special_addr);
+  fprintf_unfiltered (file, "}");
 }
 
 static void
@@ -152,9 +145,6 @@ fprint_frame_type (struct ui_file *file, enum frame_type type)
 {
   switch (type)
     {
-    case UNKNOWN_FRAME:
-      fprintf_unfiltered (file, "UNKNOWN_FRAME");
-      return;
     case NORMAL_FRAME:
       fprintf_unfiltered (file, "NORMAL_FRAME");
       return;
@@ -182,7 +172,10 @@ fprint_frame (struct ui_file *file, struct frame_info *fi)
   fprintf_unfiltered (file, "level=%d", fi->level);
   fprintf_unfiltered (file, ",");
   fprintf_unfiltered (file, "type=");
-  fprint_frame_type (file, fi->type);
+  if (fi->unwind != NULL)
+    fprint_frame_type (file, fi->unwind->type);
+  else
+    fprintf_unfiltered (file, "<unknown>");
   fprintf_unfiltered (file, ",");
   fprintf_unfiltered (file, "unwind=");
   if (fi->unwind != NULL)
@@ -222,23 +215,13 @@ get_frame_id (struct frame_info *fi)
     }
   if (!fi->this_id.p)
     {
-      gdb_assert (!legacy_frame_p (current_gdbarch));
       if (frame_debug)
        fprintf_unfiltered (gdb_stdlog, "{ get_frame_id (fi=%d) ",
                            fi->level);
       /* Find the unwinder.  */
       if (fi->unwind == NULL)
-       {
-         fi->unwind = frame_unwind_find_by_pc (current_gdbarch,
-                                               get_frame_pc (fi));
-         /* 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 (fi->unwind->type != UNKNOWN_FRAME);
-         fi->type = fi->unwind->type;
-       }
+       fi->unwind = frame_unwind_find_by_frame (fi->next,
+                                                &fi->prologue_cache);
       /* Find THIS frame's ID.  */
       fi->unwind->this_id (fi->next, &fi->prologue_cache, &fi->this_id.value);
       fi->this_id.p = 1;
@@ -252,14 +235,49 @@ get_frame_id (struct frame_info *fi)
   return fi->this_id.value;
 }
 
+struct frame_id
+frame_unwind_id (struct frame_info *next_frame)
+{
+  /* Use prev_frame, and not get_prev_frame.  The latter will truncate
+     the frame chain, leading to this function unintentionally
+     returning a null_frame_id (e.g., when a caller requests the frame
+     ID of "main()"s caller.  */
+  return get_frame_id (get_prev_frame_1 (next_frame));
+}
+
 const struct frame_id null_frame_id; /* All zeros.  */
 
+struct frame_id
+frame_id_build_special (CORE_ADDR stack_addr, CORE_ADDR code_addr,
+                        CORE_ADDR special_addr)
+{
+  struct frame_id id = null_frame_id;
+  id.stack_addr = stack_addr;
+  id.stack_addr_p = 1;
+  id.code_addr = code_addr;
+  id.code_addr_p = 1;
+  id.special_addr = special_addr;
+  id.special_addr_p = 1;
+  return id;
+}
+
 struct frame_id
 frame_id_build (CORE_ADDR stack_addr, CORE_ADDR code_addr)
 {
-  struct frame_id id;
+  struct frame_id id = null_frame_id;
   id.stack_addr = stack_addr;
+  id.stack_addr_p = 1;
   id.code_addr = code_addr;
+  id.code_addr_p = 1;
+  return id;
+}
+
+struct frame_id
+frame_id_build_wild (CORE_ADDR stack_addr)
+{
+  struct frame_id id = null_frame_id;
+  id.stack_addr = stack_addr;
+  id.stack_addr_p = 1;
   return id;
 }
 
@@ -267,8 +285,8 @@ int
 frame_id_p (struct frame_id l)
 {
   int p;
-  /* The .code can be NULL but the .stack cannot.  */
-  p = (l.stack_addr != 0);
+  /* The frame is valid iff it has a valid stack address.  */
+  p = l.stack_addr_p;
   if (frame_debug)
     {
       fprintf_unfiltered (gdb_stdlog, "{ frame_id_p (l=");
@@ -282,17 +300,24 @@ int
 frame_id_eq (struct frame_id l, struct frame_id r)
 {
   int eq;
-  if (l.stack_addr == 0 || r.stack_addr == 0)
-    /* Like a NaN, if either ID is invalid, the result is false.  */
+  if (!l.stack_addr_p || !r.stack_addr_p)
+    /* Like a NaN, if either ID is invalid, the result is false.
+       Note that a frame ID is invalid iff it is the null frame ID.  */
     eq = 0;
   else if (l.stack_addr != r.stack_addr)
     /* If .stack addresses are different, the frames are different.  */
     eq = 0;
-  else if (l.code_addr == 0 || r.code_addr == 0)
-    /* A zero code addr is a wild card, always succeed.  */
+  else if (!l.code_addr_p || !r.code_addr_p)
+    /* An invalid code addr is a wild card, always succeed.  */
+    eq = 1;
+  else if (l.code_addr != r.code_addr)
+    /* If .code addresses are different, the frames are different.  */
+    eq = 0;
+  else if (!l.special_addr_p || !r.special_addr_p)
+    /* An invalid special addr is a wild card (or unused), always succeed.  */
     eq = 1;
-  else if (l.code_addr == r.code_addr)
-    /* The .stack and .code are identical, the ID's are identical.  */
+  else if (l.special_addr == r.special_addr)
+    /* Frames are equal.  */
     eq = 1;
   else
     /* No luck.  */
@@ -312,14 +337,14 @@ int
 frame_id_inner (struct frame_id l, struct frame_id r)
 {
   int inner;
-  if (l.stack_addr == 0 || r.stack_addr == 0)
+  if (!l.stack_addr_p || !r.stack_addr_p)
     /* Like NaN, any operation involving an invalid ID always fails.  */
     inner = 0;
   else
     /* 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 .stack but
-       different .code).  */
+       different .code and/or .special address).  */
     inner = INNER_THAN (l.stack_addr, r.stack_addr);
   if (frame_debug)
     {
@@ -353,8 +378,8 @@ frame_find_by_id (struct frame_id id)
       if (frame_id_inner (id, this))
        /* Gone to far.  */
        return NULL;
-      /* Either, we're not yet gone far enough out along the frame
-         chain (inner(this,id), or we're comparing frameless functions
+      /* 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.  */
     }
@@ -367,7 +392,15 @@ frame_pc_unwind (struct frame_info *this_frame)
   if (!this_frame->prev_pc.p)
     {
       CORE_ADDR pc;
-      if (gdbarch_unwind_pc_p (current_gdbarch))
+      if (this_frame->unwind == NULL)
+       this_frame->unwind
+         = frame_unwind_find_by_frame (this_frame->next,
+                                       &this_frame->prologue_cache);
+      if (this_frame->unwind->prev_pc != NULL)
+       /* A per-frame unwinder, prefer it.  */
+       pc = this_frame->unwind->prev_pc (this_frame->next,
+                                         &this_frame->prologue_cache);
+      else 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
@@ -387,25 +420,8 @@ frame_pc_unwind (struct frame_info *this_frame)
             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");
+       internal_error (__FILE__, __LINE__, _("No unwind_pc method"));
       this_frame->prev_pc.value = pc;
       this_frame->prev_pc.p = 1;
       if (frame_debug)
@@ -422,8 +438,11 @@ frame_func_unwind (struct frame_info *fi)
 {
   if (!fi->prev_func.p)
     {
+      /* Make certain that this, and not the adjacent, function is
+         found.  */
+      CORE_ADDR addr_in_block = frame_unwind_address_in_block (fi);
       fi->prev_func.p = 1;
-      fi->prev_func.addr = get_pc_function_start (frame_pc_unwind (fi));
+      fi->prev_func.addr = get_pc_function_start (addr_in_block);
       if (frame_debug)
        fprintf_unfiltered (gdb_stdlog,
                            "{ frame_func_unwind (fi=%d) -> 0x%s }\n",
@@ -439,48 +458,46 @@ get_frame_func (struct frame_info *fi)
 }
 
 static int
-do_frame_unwind_register (void *src, int regnum, void *buf)
+do_frame_register_read (void *src, int regnum, void *buf)
 {
-  frame_unwind_register (src, regnum, buf);
+  frame_register_read (src, regnum, buf);
   return 1;
 }
 
+struct regcache *
+frame_save_as_regcache (struct frame_info *this_frame)
+{
+  struct regcache *regcache = regcache_xmalloc (current_gdbarch);
+  struct cleanup *cleanups = make_cleanup_regcache_xfree (regcache);
+  regcache_save (regcache, do_frame_register_read, this_frame);
+  discard_cleanups (cleanups);
+  return regcache;
+}
+
 void
 frame_pop (struct frame_info *this_frame)
 {
-  struct regcache *scratch_regcache;
-  struct cleanup *cleanups;
+  /* 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 between
+     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
+    = frame_save_as_regcache (get_prev_frame_1 (this_frame));
+  struct cleanup *cleanups = make_cleanup_regcache_xfree (scratch);
+
+  /* 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.
+     Unfortunately, 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);
 
-  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
-    {
-      /* 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);
-    }
   /* We've made right mess of GDB's local state, just discard
      everything.  */
   flush_cached_frames ();
@@ -495,9 +512,10 @@ frame_register_unwind (struct frame_info *frame, int regnum,
 
   if (frame_debug)
     {
-      fprintf_unfiltered (gdb_stdlog,
-                         "{ frame_register_unwind (frame=%d,regnum=\"%s\",...) ",
-                         frame->level, frame_map_regnum_to_name (regnum));
+      fprintf_unfiltered (gdb_stdlog, "\
+{ frame_register_unwind (frame=%d,regnum=%d(%s),...) ",
+                         frame->level, regnum,
+                         frame_map_regnum_to_name (frame, regnum));
     }
 
   /* Require all but BUFFERP to be valid.  A NULL BUFFERP indicates
@@ -510,26 +528,17 @@ frame_register_unwind (struct frame_info *frame, int regnum,
 
   /* 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
+     isn't a frame, there is some pretty busted code as it should have
      detected the problem before calling here.  */
   gdb_assert (frame != NULL);
 
   /* Find the unwinder.  */
   if (frame->unwind == NULL)
-    {
-      frame->unwind = frame_unwind_find_by_pc (current_gdbarch,
-                                              get_frame_pc (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 (frame->unwind->type != UNKNOWN_FRAME);
-      frame->type = frame->unwind->type;
-    }
+    frame->unwind = frame_unwind_find_by_frame (frame->next,
+                                               &frame->prologue_cache);
 
   /* Ask this frame to unwind its register.  See comment in
-     "frame-unwind.h" for why NEXT frame and this unwind cace are
+     "frame-unwind.h" for why NEXT frame and this unwind cache are
      passed in.  */
   frame->unwind->prev_register (frame->next, &frame->prologue_cache, regnum,
                                optimizedp, lvalp, addrp, realnump, bufferp);
@@ -546,7 +555,7 @@ frame_register_unwind (struct frame_info *frame, int regnum,
       else
        {
          int i;
-         const char *buf = bufferp;
+         const unsigned char *buf = bufferp;
          fprintf_unfiltered (gdb_stdlog, "[");
          for (i = 0; i < register_size (current_gdbarch, regnum); i++)
            fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]);
@@ -569,33 +578,6 @@ frame_register (struct frame_info *frame, int regnum,
   gdb_assert (realnump != NULL);
   /* gdb_assert (bufferp != NULL); */
 
-  /* 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 (DEPRECATED_GET_SAVED_REGISTER_P ())
-    {
-      DEPRECATED_GET_SAVED_REGISTER (bufferp, optimizedp, addrp, frame,
-                                    regnum, lvalp);
-      /* Compute the REALNUM if the caller wants it.  */
-      if (*lvalp == lval_register)
-       {
-         int regnum;
-         for (regnum = 0; regnum < NUM_REGS + NUM_PSEUDO_REGS; regnum++)
-           {
-             if (*addrp == register_offset_hack (current_gdbarch, regnum))
-               {
-                 *realnump = regnum;
-                 return;
-               }
-           }
-         internal_error (__FILE__, __LINE__,
-                         "Failed to compute the register number corresponding"
-                         " to 0x%s", paddr_d (*addrp));
-       }
-      *realnump = -1;
-      return;
-    }
-
   /* Obtain the register value by unwinding the register from the next
      (more inner frame).  */
   gdb_assert (frame != NULL && frame->next != NULL);
@@ -615,98 +597,87 @@ frame_unwind_register (struct frame_info *frame, int regnum, void *buf)
 }
 
 void
-frame_unwind_signed_register (struct frame_info *frame, int regnum,
-                             LONGEST *val)
+get_frame_register (struct frame_info *frame,
+                   int regnum, void *buf)
 {
-  char buf[MAX_REGISTER_SIZE];
-  frame_unwind_register (frame, regnum, buf);
-  (*val) = extract_signed_integer (buf, REGISTER_VIRTUAL_SIZE (regnum));
+  frame_unwind_register (frame->next, regnum, buf);
 }
 
-void
-frame_unwind_unsigned_register (struct frame_info *frame, int regnum,
-                               ULONGEST *val)
+LONGEST
+frame_unwind_register_signed (struct frame_info *frame, int regnum)
 {
   char buf[MAX_REGISTER_SIZE];
   frame_unwind_register (frame, regnum, buf);
-  (*val) = extract_unsigned_integer (buf, REGISTER_VIRTUAL_SIZE (regnum));
+  return extract_signed_integer (buf, register_size (get_frame_arch (frame),
+                                                    regnum));
 }
 
-void
-frame_read_register (struct frame_info *frame, int regnum, void *buf)
+LONGEST
+get_frame_register_signed (struct frame_info *frame, int regnum)
 {
-  gdb_assert (frame != NULL && frame->next != NULL);
-  frame_unwind_register (frame->next, regnum, buf);
+  return frame_unwind_register_signed (frame->next, regnum);
 }
 
-void
-frame_read_unsigned_register (struct frame_info *frame, int regnum,
-                             ULONGEST *val)
-{
-  /* NOTE: cagney/2002-10-31: There is a bit of dogma here - there is
-     always a frame.  Both this, and the equivalent
-     frame_read_signed_register() function, can only be called with a
-     valid frame.  If, for some reason, this function is called
-     without a frame then the problem isn't here, but rather in the
-     caller.  It should of first created a frame and then passed that
-     in.  */
-  /* NOTE: cagney/2002-10-31: As a side bar, keep in mind that the
-     ``current_frame'' should not be treated as a special case.  While
-     ``get_next_frame (current_frame) == NULL'' currently holds, it
-     should, as far as possible, not be relied upon.  In the future,
-     ``get_next_frame (current_frame)'' may instead simply return a
-     normal frame object that simply always gets register values from
-     the register cache.  Consequently, frame code should try to avoid
-     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->next != NULL);
-  frame_unwind_unsigned_register (frame->next, regnum, val);
+ULONGEST
+frame_unwind_register_unsigned (struct frame_info *frame, int regnum)
+{
+  char buf[MAX_REGISTER_SIZE];
+  frame_unwind_register (frame, regnum, buf);
+  return extract_unsigned_integer (buf, register_size (get_frame_arch (frame),
+                                                      regnum));
 }
 
-void
-frame_read_signed_register (struct frame_info *frame, int regnum,
-                           LONGEST *val)
+ULONGEST
+get_frame_register_unsigned (struct frame_info *frame, int regnum)
 {
-  /* See note above in frame_read_unsigned_register().  */
-  gdb_assert (frame != NULL && frame->next != NULL);
-  frame_unwind_signed_register (frame->next, regnum, val);
+  return frame_unwind_register_unsigned (frame->next, regnum);
 }
 
 void
-deprecated_unwind_get_saved_register (char *raw_buffer,
-                                     int *optimizedp,
-                                     CORE_ADDR *addrp,
-                                     struct frame_info *frame,
-                                     int regnum,
-                                     enum lval_type *lvalp)
-{
-  int optimizedx;
-  CORE_ADDR addrx;
-  int realnumx;
-  enum lval_type lvalx;
-
-  if (!target_has_registers)
-    error ("No registers.");
-
-  /* Keep things simple, ensure that all the pointers (except valuep)
-     are non NULL.  */
-  if (optimizedp == NULL)
-    optimizedp = &optimizedx;
-  if (lvalp == NULL)
-    lvalp = &lvalx;
-  if (addrp == NULL)
-    addrp = &addrx;
+frame_unwind_unsigned_register (struct frame_info *frame, int regnum,
+                               ULONGEST *val)
+{
+  char buf[MAX_REGISTER_SIZE];
+  frame_unwind_register (frame, regnum, buf);
+  (*val) = extract_unsigned_integer (buf,
+                                    register_size (get_frame_arch (frame),
+                                                   regnum));
+}
 
-  gdb_assert (frame != NULL && frame->next != NULL);
-  frame_register_unwind (frame->next, regnum, optimizedp, lvalp, addrp,
-                        &realnumx, raw_buffer);
+void
+put_frame_register (struct frame_info *frame, int regnum, const void *buf)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  int realnum;
+  int optim;
+  enum lval_type lval;
+  CORE_ADDR addr;
+  frame_register (frame, regnum, &optim, &lval, &addr, &realnum, NULL);
+  if (optim)
+    error (_("Attempt to assign to a value that was optimized out."));
+  switch (lval)
+    {
+    case lval_memory:
+      {
+       /* FIXME: write_memory doesn't yet take constant buffers.
+           Arrrg!  */
+       char tmp[MAX_REGISTER_SIZE];
+       memcpy (tmp, buf, register_size (gdbarch, regnum));
+       write_memory (addr, tmp, register_size (gdbarch, regnum));
+       break;
+      }
+    case lval_register:
+      regcache_cooked_write (current_regcache, realnum, buf);
+      break;
+    default:
+      error (_("Attempt to assign to an unmodifiable value."));
+    }
 }
 
 /* frame_register_read ()
 
    Find and return the value of REGNUM for the specified stack frame.
-   The number of bytes copied is REGISTER_RAW_SIZE (REGNUM).
+   The number of bytes copied is REGISTER_SIZE (REGNUM).
 
    Returns 0 if the register value could not be found.  */
 
@@ -719,7 +690,7 @@ frame_register_read (struct frame_info *frame, int regnum, void *myaddr)
   int realnum;
   frame_register (frame, regnum, &optimized, &lval, &addr, &realnum, myaddr);
 
-  /* FIXME: cagney/2002-05-15: This test, is just bogus.
+  /* FIXME: cagney/2002-05-15: This test is just bogus.
 
      It indicates that the target failed to supply a value for a
      register because it was "not available" at this time.  Problem
@@ -738,42 +709,15 @@ frame_register_read (struct frame_info *frame, int regnum, void *myaddr)
    includes builtin registers.  */
 
 int
-frame_map_name_to_regnum (const char *name, int len)
+frame_map_name_to_regnum (struct frame_info *frame, 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))
-       && strncmp (name, REGISTER_NAME (i), len) == 0)
-      {
-       return i;
-      }
-
-  /* Try builtin registers.  */
-  i = builtin_reg_map_name_to_regnum (name, len);
-  if (i >= 0)
-    {
-      /* A builtin register doesn't fall into the architecture's
-         register range.  */
-      gdb_assert (i >= NUM_REGS + NUM_PSEUDO_REGS);
-      return i;
-    }
-
-  return -1;
+  return user_reg_map_name_to_regnum (get_frame_arch (frame), name, len);
 }
 
 const char *
-frame_map_regnum_to_name (int regnum)
+frame_map_regnum_to_name (struct frame_info *frame, int regnum)
 {
-  if (regnum < 0)
-    return NULL;
-  if (regnum < NUM_REGS + NUM_PSEUDO_REGS)
-    return REGISTER_NAME (regnum);
-  return builtin_reg_map_regnum_to_name (regnum);
+  return user_reg_map_regnum_to_name (get_frame_arch (frame), regnum);
 }
 
 /* Create a sentinel frame.  */
@@ -782,7 +726,6 @@ static 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
@@ -824,20 +767,6 @@ frame_obstack_zalloc (unsigned long size)
   return data;
 }
 
-CORE_ADDR *
-frame_saved_regs_zalloc (struct frame_info *fi)
-{
-  fi->saved_regs = (CORE_ADDR *)
-    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.  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
@@ -847,7 +776,7 @@ 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
+  /* A sentinel frame can fail to unwind, e.g., because its PC value
      lands in somewhere like start.  */
   if (frame == NULL)
     return 1;
@@ -864,17 +793,17 @@ get_current_frame (void)
      explicitly checks that ``print $pc'' with no registers prints "No
      registers".  */
   if (!target_has_registers)
-    error ("No registers.");
+    error (_("No registers."));
   if (!target_has_stack)
-    error ("No stack.");
+    error (_("No stack."));
   if (!target_has_memory)
-    error ("No memory.");
+    error (_("No memory."));
   if (current_frame == NULL)
     {
       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)
+                           RETURN_MASK_ERROR) != 0)
        {
          /* Oops! Fake a current frame?  Is this useful?  It has a PC
              of zero, for instance.  */
@@ -889,50 +818,74 @@ get_current_frame (void)
 
 struct frame_info *deprecated_selected_frame;
 
-/* Return the selected frame.  Always non-null (unless there isn't an
+/* 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)
+get_selected_frame (const char *message)
 {
   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 ());
+    {
+      if (message != NULL && (!target_has_registers
+                             || !target_has_stack
+                             || !target_has_memory))
+       error (("%s"), message);
+      /* 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;
 }
 
+/* This is a variant of get_selected_frame() which can be called when
+   the inferior does not have a frame; in that case it will return
+   NULL instead of calling error().  */
+
+struct frame_info *
+deprecated_safe_get_selected_frame (void)
+{
+  if (!target_has_registers || !target_has_stack || !target_has_memory)
+    return NULL;
+  return get_selected_frame (NULL);
+}
+
 /* Select frame FI (or NULL - to invalidate the current frame).  */
 
 void
 select_frame (struct frame_info *fi)
 {
-  register struct symtab *s;
+  struct symtab *s;
 
   deprecated_selected_frame = fi;
-  /* NOTE: cagney/2002-05-04: FI can be NULL.  This occures when the
+  /* NOTE: cagney/2002-05-04: FI can be NULL.  This occurs when the
      frame is being invalidated.  */
-  if (selected_frame_level_changed_hook)
-    selected_frame_level_changed_hook (frame_relative_level (fi));
+  if (deprecated_selected_frame_level_changed_hook)
+    deprecated_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
+     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.
+     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. */
+     be called when the user's 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));
+      /* We retrieve the frame's symtab by using the frame PC.  However
+         we cannot use the frame PC as-is, because it usually points to
+         the instruction following the "call", which is sometimes the
+         first instruction of another function.  So we rely on
+         get_frame_address_in_block() which provides us with a PC which
+         is guaranteed to be inside the frame's code block.  */
+      s = find_pc_symtab (get_frame_address_in_block (fi));
       if (s
          && s->language != current_language->la_language
          && s->language != language_unknown
@@ -942,244 +895,7 @@ select_frame (struct frame_info *fi)
        }
     }
 }
-
-/* Return the register saved in the simplistic ``saved_regs'' cache.
-   If the value isn't here AND a value is needed, try the next inner
-   most frame.  */
-
-static void
-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)
-{
-  /* 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);
-
-  /* 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 (get_frame_saved_regs (frame) == NULL)
-    DEPRECATED_FRAME_INIT_SAVED_REGS (frame);
-
-  if (get_frame_saved_regs (frame) != NULL
-      && get_frame_saved_regs (frame)[regnum] != 0)
-    {
-      if (regnum == SP_REGNUM)
-       {
-         /* SP register treated specially.  */
-         *optimizedp = 0;
-         *lvalp = not_lval;
-         *addrp = 0;
-         *realnump = -1;
-         if (bufferp != NULL)
-           /* NOTE: cagney/2003-05-09: In-lined store_address with
-               it's body - store_unsigned_integer.  */
-           store_unsigned_integer (bufferp, REGISTER_RAW_SIZE (regnum),
-                                   get_frame_saved_regs (frame)[regnum]);
-       }
-      else
-       {
-         /* Any other register is saved in memory, fetch it but cache
-             a local copy of its value.  */
-         *optimizedp = 0;
-         *lvalp = lval_memory;
-         *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 = (*this_prologue_cache);
-             if (regs == NULL)
-               {
-                 int sizeof_cache = ((NUM_REGS + NUM_PSEUDO_REGS)
-                                     * sizeof (void *));
-                 regs = frame_obstack_zalloc (sizeof_cache);
-                 (*this_prologue_cache) = regs;
-               }
-             if (regs[regnum] == NULL)
-               {
-                 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 (get_frame_saved_regs (frame)[regnum], bufferp,
-                          REGISTER_RAW_SIZE (regnum));
-#endif
-           }
-       }
-      return;
-    }
-
-  /* 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)
-{
-  /* legacy_get_prev_frame() always sets ->this_id.p, hence this is
-     never needed.  */
-  internal_error (__FILE__, __LINE__, "legacy_saved_regs_this_id() called");
-}
        
-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.
-
-   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
-   in this implementation.
-
-   Set *LVAL to lval_memory, lval_register, or not_lval, depending on
-   whether the value was fetched from memory, from a register, or in a
-   strange and non-modifiable way (e.g. a frame pointer which was
-   calculated rather than fetched).  We will use not_lval for values
-   fetched from generic dummy frames.
-
-   Set *ADDRP to the address, either in memory or as a REGISTER_BYTE
-   offset into the registers array.  If the value is stored in a dummy
-   frame, set *ADDRP to zero.
-
-   The argument RAW_BUFFER must point to aligned memory.  */
-
-void
-deprecated_generic_get_saved_register (char *raw_buffer, int *optimized,
-                                      CORE_ADDR *addrp,
-                                      struct frame_info *frame, int regnum,
-                                      enum lval_type *lval)
-{
-  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;
-
-  if (addrp)                   /* default assumption: not found in memory */
-    *addrp = 0;
-
-  /* Note: since the current frame's registers could only have been
-     saved by frames INTERIOR TO the current frame, we skip examining
-     the current frame itself: otherwise, we would be getting the
-     previous frame's registers which were saved by the current frame.  */
-
-  if (frame != NULL)
-    {
-      for (frame = get_next_frame (frame);
-          frame_relative_level (frame) >= 0;
-          frame = get_next_frame (frame))
-       {
-         if (get_frame_type (frame) == DUMMY_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
-                 (deprecated_find_dummy_frame_regcache (get_frame_pc (frame),
-                                                        get_frame_base (frame)),
-                  regnum, raw_buffer);
-             return;
-           }
-
-         DEPRECATED_FRAME_INIT_SAVED_REGS (frame);
-         if (get_frame_saved_regs (frame) != NULL
-             && get_frame_saved_regs (frame)[regnum] != 0)
-           {
-             if (lval)         /* found it saved on the stack */
-               *lval = lval_memory;
-             if (regnum == SP_REGNUM)
-               {
-                 if (raw_buffer)       /* SP register treated specially */
-                   /* NOTE: cagney/2003-05-09: In-line store_address
-                       with it's body - store_unsigned_integer.  */
-                   store_unsigned_integer (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;
-           }
-       }
-    }
-
-  /* If we get thru the loop to this point, it means the register was
-     not saved in any frame.  Return the actual live-register value.  */
-
-  if (lval)                    /* found it in a live register */
-    *lval = lval_register;
-  if (addrp)
-    *addrp = REGISTER_BYTE (regnum);
-  if (raw_buffer)
-    deprecated_read_register_gen (regnum, raw_buffer);
-}
-
-/* Determine the frame's type based on its PC.  */
-
-static enum frame_type
-frame_type_from_pc (CORE_ADDR pc)
-{
-  /* 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
-    {
-      char *name;
-      find_pc_partial_function (pc, &name, NULL, NULL);
-      if (PC_IN_SIGTRAMP (pc, name))
-       return SIGTRAMP_FRAME;
-      else
-       return NORMAL_FRAME;
-    }
-}
-
 /* Create an arbitrary (i.e. address specified by user) or innermost frame.
    Always returns a non-NULL value.  */
 
@@ -1201,19 +917,12 @@ create_new_frame (CORE_ADDR addr, CORE_ADDR 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);
+  fi->unwind = frame_unwind_find_by_frame (fi->next, &fi->prologue_cache);
 
   fi->this_id.p = 1;
   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);
-
   if (frame_debug)
     {
       fprintf_unfiltered (gdb_stdlog, "-> ");
@@ -1237,6 +946,14 @@ get_next_frame (struct frame_info *this_frame)
     return NULL;
 }
 
+/* Observer for the target_changed event.  */
+
+void
+frame_observer_target_changed (struct target_ops *target)
+{
+  flush_cached_frames ();
+}
+
 /* Flush the entire frame cache.  */
 
 void
@@ -1267,453 +984,127 @@ reinit_frame_cache (void)
     }
 }
 
-/* Create the previous frame using the deprecated methods
-   INIT_EXTRA_INFO, INIT_FRAME_PC and INIT_FRAME_PC_FIRST.  */
+/* Return a "struct frame_info" corresponding to the frame that called
+   THIS_FRAME.  Returns NULL if there is no such frame.
+
+   Unlike get_prev_frame, this function always tries to unwind the
+   frame.  */
 
 static struct frame_info *
-legacy_get_prev_frame (struct frame_info *this_frame)
+get_prev_frame_1 (struct frame_info *this_frame)
 {
-  CORE_ADDR address = 0;
-  struct frame_info *prev;
-  int fromleaf;
-
-  /* Don't frame_debug print legacy_get_prev_frame() here, just
-     confuses the output.  */
+  struct frame_info *prev_frame;
+  struct frame_id this_id;
 
-  /* Allocate the new frame.
+  gdb_assert (this_frame != NULL);
 
-     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->this_id.p = 1;
-
-  /* Handle sentinel frame unwind as a special case.  */
-  if (this_frame->level < 0)
+  if (frame_debug)
     {
-      /* 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, "-> ");
-             fprint_frame (gdb_stdlog, NULL);
-             fprintf_unfiltered (gdb_stdlog,
-                                 " // unwound legacy PC zero }\n");
-           }
-         return NULL;
-       }
-
-      /* 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
-         && 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->this_id.value = gdbarch_unwind_dummy_id (current_gdbarch,
-                                                        this_frame);
-       }
+      fprintf_unfiltered (gdb_stdlog, "{ get_prev_frame_1 (this_frame=");
+      if (this_frame != NULL)
+       fprintf_unfiltered (gdb_stdlog, "%d", this_frame->level);
       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->this_id.value = frame_id_build (deprecated_read_fp (),
-                                               read_pc ());
-       }
-
-      /* Check that the unwound ID is valid.  */
-      if (!frame_id_p (prev->this_id.value))
-       {
-         if (frame_debug)
-           {
-             fprintf_unfiltered (gdb_stdlog, "-> ");
-             fprint_frame (gdb_stdlog, NULL);
-             fprintf_unfiltered (gdb_stdlog,
-                                 " // unwound legacy 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.  */
-
-      /* 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);
-       }
-
-      if (prev->type == NORMAL_FRAME)
-       prev->this_id.value.code_addr
-         = get_pc_function_start (prev->this_id.value.code_addr);
-
-      if (frame_debug)
-       {
-         fprintf_unfiltered (gdb_stdlog, "-> ");
-         fprint_frame (gdb_stdlog, prev);
-         fprintf_unfiltered (gdb_stdlog, " } // legacy innermost frame\n");
-       }
-      return prev;
+       fprintf_unfiltered (gdb_stdlog, "<NULL>");
+      fprintf_unfiltered (gdb_stdlog, ") ");
     }
 
-  /* 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
-     define this macro to take two args; a frameinfo pointer
-     identifying a frame and a variable to set or clear if it is
-     or isn't leafless.  */
-
-  /* Still don't want to worry about this except on the innermost
-     frame.  This macro will set FROMLEAF if THIS_FRAME is a frameless
-     function invocation.  */
-  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 (this_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.  */
-    address = get_frame_base (this_frame);
-  else
-    {
-      /* 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 ());
-      address = DEPRECATED_FRAME_CHAIN (this_frame);
-
-      if (!legacy_frame_chain_valid (address, this_frame))
-       {
-         if (frame_debug)
-           {
-             fprintf_unfiltered (gdb_stdlog, "-> ");
-             fprint_frame (gdb_stdlog, NULL);
-             fprintf_unfiltered (gdb_stdlog,
-                                 " // legacy frame chain invalid }\n");
-           }
-         return NULL;
-       }
-    }
-  if (address == 0)
+  /* Only try to do the unwind once.  */
+  if (this_frame->prev_p)
     {
       if (frame_debug)
        {
          fprintf_unfiltered (gdb_stdlog, "-> ");
-         fprint_frame (gdb_stdlog, NULL);
-         fprintf_unfiltered (gdb_stdlog,
-                             " // legacy frame chain NULL }\n");
+         fprint_frame (gdb_stdlog, this_frame->prev);
+         fprintf_unfiltered (gdb_stdlog, " // cached \n");
        }
-      return NULL;
+      return this_frame->prev;
     }
+  this_frame->prev_p = 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* 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.
-
-     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 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 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 DEPRECATED_INIT_FRAME_PC after
-     DEPRECATED_INIT_EXTRA_FRAME_INFO, one possible scheme:
-
-     SETUP_INNERMOST_FRAME(): Default version is just create_new_frame
-     (deprecated_read_fp ()), read_pc ()).  Machines with extra frame
-     info would do that (or the local equivalent) and then set the
-     extra fields.
-
-     SETUP_ARBITRARY_FRAME(argc, argv): Only change here is that
-     create_new_frame would no longer init extra frame info;
-     SETUP_ARBITRARY_FRAME would have to do that.
-
-     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 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.  */
-
-  /* NOTE: cagney/2002-11-09: Just ignore the above!  There is no
-     reason for things to be this complicated.
-
-     The trick is to assume that there is always a frame.  Instead of
-     special casing the inner-most frame, create fake frame
-     (containing the hardware registers) that is inner to the
-     user-visible inner-most frame (...) and then unwind from that.
-     That way architecture code can use use the standard
-     frame_XX_unwind() functions and not differentiate between the
-     inner most and any other case.
-
-     Since there is always a frame to unwind from, there is always
-     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 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.  */
-
-  if (DEPRECATED_INIT_FRAME_PC_FIRST_P ())
-    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);
-
-  /* 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. */
-  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 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))
+  /* 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.  */
+  this_id = get_frame_id (this_frame);
+  if (this_frame->level >= 0 && !frame_id_p (this_id))
     {
-      this_frame->prev = NULL;
-      obstack_free (&frame_cache_obstack, prev);
       if (frame_debug)
        {
          fprintf_unfiltered (gdb_stdlog, "-> ");
          fprint_frame (gdb_stdlog, NULL);
-         fprintf_unfiltered (gdb_stdlog,
-                             " // legacy this.id == prev.id }\n");
+         fprintf_unfiltered (gdb_stdlog, " // this ID is NULL }\n");
        }
       return NULL;
     }
 
-  /* Initialize the code used to unwind the frame PREV based on the PC
-     (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,
-                                         get_frame_pc (prev));
+  /* Check that this frame's ID isn't inner to (younger, below, next)
+     the next frame.  This happens when a frame unwind goes backwards.
+     Exclude signal trampolines (due to sigaltstack the frame ID can
+     go backwards) and sentinel frames (the test is meaningless).  */
+  if (this_frame->next->level >= 0
+      && this_frame->next->unwind->type != SIGTRAMP_FRAME
+      && frame_id_inner (this_id, get_frame_id (this_frame->next)))
+    error (_("Previous frame inner to this frame (corrupt stack?)"));
+
+  /* Check that this and the next frame are not identical.  If they
+     are, there is most likely a stack cycle.  As with the inner-than
+     test above, avoid comparing the inner-most and sentinel frames.  */
+  if (this_frame->level > 0
+      && frame_id_eq (this_id, get_frame_id (this_frame->next)))
+    error (_("Previous frame identical to this 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.
 
-  /* 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;
-      if (prev->type == NORMAL_FRAME)
-       prev->this_id.value.code_addr
-         = get_pc_function_start (prev->this_id.value.code_addr);
-      if (frame_debug)
-       {
-         fprintf_unfiltered (gdb_stdlog, "-> ");
-         fprint_frame (gdb_stdlog, prev);
-         fprintf_unfiltered (gdb_stdlog, " } // legacy with unwound type\n");
-       }
-      return prev;
-    }
+     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;
 
-  /* 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.  */
-    }
+  /* Don't yet compute ->unwind (and hence ->type).  It is computed
+     on-demand in get_frame_type, frame_register_unwind, and
+     get_frame_id.  */
 
-  if (prev->type == NORMAL_FRAME)
-    prev->this_id.value.code_addr
-      = get_pc_function_start (prev->this_id.value.code_addr);
+  /* Don't yet compute the frame's ID.  It is computed on-demand by
+     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.
+
+     Some very old VAX code 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;
 
   if (frame_debug)
     {
       fprintf_unfiltered (gdb_stdlog, "-> ");
-      fprint_frame (gdb_stdlog, prev);
-      fprintf_unfiltered (gdb_stdlog, " } // legacy with confused type\n");
+      fprint_frame (gdb_stdlog, prev_frame);
+      fprintf_unfiltered (gdb_stdlog, " }\n");
     }
 
-  return prev;
+  return prev_frame;
 }
 
-/* Return a structure containing various interesting information
-   about the frame that called THIS_FRAME.  Returns NULL
-   if there is no such frame.  */
+/* Debug routine to print a NULL frame being returned.  */
 
-struct frame_info *
-get_prev_frame (struct frame_info *this_frame)
+static void
+frame_debug_got_null_frame (struct ui_file *file,
+                           struct frame_info *this_frame,
+                           const char *reason)
 {
-  struct frame_info *prev_frame;
-
   if (frame_debug)
     {
       fprintf_unfiltered (gdb_stdlog, "{ get_prev_frame (this_frame=");
@@ -1721,8 +1112,52 @@ get_prev_frame (struct frame_info *this_frame)
        fprintf_unfiltered (gdb_stdlog, "%d", this_frame->level);
       else
        fprintf_unfiltered (gdb_stdlog, "<NULL>");
-      fprintf_unfiltered (gdb_stdlog, ") ");
+      fprintf_unfiltered (gdb_stdlog, ") -> // %s}\n", reason);
     }
+}
+
+/* Is this (non-sentinel) frame in the "main"() function?  */
+
+static int
+inside_main_func (struct frame_info *this_frame)
+{
+  struct minimal_symbol *msymbol;
+  CORE_ADDR maddr;
+
+  if (symfile_objfile == 0)
+    return 0;
+  msymbol = lookup_minimal_symbol (main_name (), NULL, symfile_objfile);
+  if (msymbol == NULL)
+    return 0;
+  /* Make certain that the code, and not descriptor, address is
+     returned.  */
+  maddr = gdbarch_convert_from_func_ptr_addr (current_gdbarch,
+                                             SYMBOL_VALUE_ADDRESS (msymbol),
+                                             &current_target);
+  return maddr == get_frame_func (this_frame);
+}
+
+/* Test whether THIS_FRAME is inside the process entry point function.  */
+
+static int
+inside_entry_func (struct frame_info *this_frame)
+{
+  return (get_frame_func (this_frame) == entry_point_address ());
+}
+
+/* Return a structure containing various interesting information about
+   the frame that called THIS_FRAME.  Returns NULL if there is entier
+   no such frame or the frame fails any of a set of target-independent
+   condition that should terminate the frame chain (e.g., as unwinding
+   past main()).
+
+   This function should not contain target-dependent tests, such as
+   checking whether the program-counter is zero.  */
+
+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
@@ -1735,9 +1170,9 @@ get_prev_frame (struct frame_info *this_frame)
      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
+     NOTE: cagney/2003-01-11: I suspect what is happening in
      block_innermost_frame() is, when the target has no state
-     (registers, memory, ...), still calling this function.  The
+     (registers, memory, ...), it is 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
@@ -1756,6 +1191,7 @@ get_prev_frame (struct frame_info *this_frame)
 
          Per the above, this code shouldn't even be called with a NULL
          THIS_FRAME.  */
+      frame_debug_got_null_frame (gdb_stdlog, this_frame, "this_frame NULL");
       return current_frame;
     }
 
@@ -1764,211 +1200,111 @@ get_prev_frame (struct frame_info *this_frame)
      get_current_frame().  */
   gdb_assert (this_frame != NULL);
 
+  /* tausq/2004-12-07: Dummy frames are skipped because it doesn't make much
+     sense to stop unwinding at a dummy frame.  One place where a dummy
+     frame may have an address "inside_main_func" is on HPUX.  On HPUX, the
+     pcsqh register (space register for the instruction at the head of the
+     instruction queue) cannot be written directly; the only way to set it
+     is to branch to code that is in the target space.  In order to implement
+     frame dummies on HPUX, the called function is made to jump back to where 
+     the inferior was when the user function was called.  If gdb was inside 
+     the main function when we created the dummy frame, the dummy frame will 
+     point inside the main function.  */
   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.  */
+      && get_frame_type (this_frame) != DUMMY_FRAME
+      && !backtrace_past_main
+      && inside_main_func (this_frame))
+    /* Don't unwind past main().  Note, this is done _before_ the
+       frame has been marked as previously unwound.  That way if the
+       user later decides to enable unwinds past main(), that will
+       automatically happen.  */
     {
-      if (frame_debug)
-       fprintf_unfiltered (gdb_stdlog, "-> NULL // inside main func }\n");
+      frame_debug_got_null_frame (gdb_stdlog, this_frame, "inside main func");
       return NULL;
     }
 
-  /* Only try to do the unwind once.  */
-  if (this_frame->prev_p)
-    {
-      if (frame_debug)
-       {
-         fprintf_unfiltered (gdb_stdlog, "-> ");
-         fprint_frame (gdb_stdlog, this_frame->prev);
-         fprintf_unfiltered (gdb_stdlog, " // cached \n");
-       }
-      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 (this_frame->level > backtrace_limit)
     {
-      if (frame_debug)
-       {
-         fprintf_unfiltered (gdb_stdlog, "-> ");
-         fprint_frame (gdb_stdlog, NULL);
-         fprintf_unfiltered (gdb_stdlog, " // inside entry file }\n");
-       }
-      return NULL;
+      error (_("Backtrace limit of %d exceeded"), backtrace_limit);
     }
-#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
+     dummy frame PCs 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, "-> ");
-         fprint_frame (gdb_stdlog, NULL);
-         fprintf_unfiltered (gdb_stdlog, "// 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);
-      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)))
+  /* NOTE: cagney/2003-07-07: Fixed a bug in inside_main_func() -
+     wasn't checking for "main" in the minimal symbols.  With that
+     fixed asm-source tests now stop in "main" instead of halting the
+     backtrace in weird and wonderful ways somewhere inside the entry
+     file.  Suspect that tests for inside the entry file/func were
+     added to work around that (now fixed) case.  */
+  /* NOTE: cagney/2003-07-15: danielj (if I'm reading it right)
+     suggested having the inside_entry_func test use the
+     inside_main_func() msymbol trick (along with entry_point_address()
+     I guess) to determine the address range of the start function.
+     That should provide a far better stopper than the current
+     heuristics.  */
+  /* NOTE: tausq/2004-10-09: this is needed if, for example, the compiler
+     applied tail-call optimizations to main so that a function called 
+     from main returns directly to the caller of main.  Since we don't
+     stop at main, we should at least stop at the entry point of the
+     application.  */
+  if (!backtrace_past_entry
+      && get_frame_type (this_frame) != DUMMY_FRAME && this_frame->level >= 0
+      && inside_entry_func (this_frame))
     {
-      if (frame_debug)
-       {
-         fprintf_unfiltered (gdb_stdlog, "-> ");
-         fprint_frame (gdb_stdlog, NULL);
-         fprintf_unfiltered (gdb_stdlog, " // this ID is NULL }\n");
-       }
+      frame_debug_got_null_frame (gdb_stdlog, this_frame, "inside entry func");
       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.  */
+  /* Assume that the only way to get a zero PC is through something
+     like a SIGSEGV or a dummy frame, and hence that NORMAL frames
+     will never unwind a zero PC.  */
   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.  */
-
-  if (frame_pc_unwind (this_frame) == 0)
+      && get_frame_type (this_frame) == NORMAL_FRAME
+      && get_frame_type (get_next_frame (this_frame)) == NORMAL_FRAME
+      && get_frame_pc (this_frame) == 0)
     {
-      /* The allocated PREV_FRAME will be reclaimed when the frame
-        obstack is next purged.  */
-      if (frame_debug)
-       {
-         fprintf_unfiltered (gdb_stdlog, "-> ");
-         fprint_frame (gdb_stdlog, NULL);
-         fprintf_unfiltered (gdb_stdlog, " // unwound PC zero }\n");
-       }
+      frame_debug_got_null_frame (gdb_stdlog, this_frame, "zero PC");
       return NULL;
     }
 
-  /* Don't yet compute ->unwind (and hence ->type).  It is computed
-     on-demand in get_frame_type, frame_register_unwind, and
-     get_frame_id.  */
-
-  /* Don't yet compute the frame's ID.  It is computed on-demand by
-     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.
+  return get_prev_frame_1 (this_frame);
+}
 
-     Some very old VAX code 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.  */
+CORE_ADDR
+get_frame_pc (struct frame_info *frame)
+{
+  gdb_assert (frame->next != NULL);
+  return frame_pc_unwind (frame->next);
+}
 
-  /* Link it in.  */
-  this_frame->prev = prev_frame;
-  prev_frame->next = this_frame;
+/* Return an address of that falls within the frame's code block.  */
 
-  if (frame_debug)
-    {
-      fprintf_unfiltered (gdb_stdlog, "-> ");
-      fprint_frame (gdb_stdlog, prev_frame);
-      fprintf_unfiltered (gdb_stdlog, " }\n");
-    }
+CORE_ADDR
+frame_unwind_address_in_block (struct frame_info *next_frame)
+{
+  /* A draft address.  */
+  CORE_ADDR pc = frame_pc_unwind (next_frame);
 
-  return prev_frame;
+  /* If THIS frame is not inner most (i.e., NEXT isn't the sentinel),
+     and NEXT is `normal' (i.e., not a sigtramp, dummy, ....) THIS
+     frame's PC ends up pointing at the instruction fallowing the
+     "call".  Adjust that PC value so that it falls on the call
+     instruction (which, hopefully, falls within THIS frame's code
+     block.  So far it's proved to be a very good approximation.  See
+     get_frame_type() for why ->type can't be used.  */
+  if (next_frame->level >= 0
+      && get_frame_type (next_frame) == NORMAL_FRAME)
+    --pc;
+  return pc;
 }
 
 CORE_ADDR
-get_frame_pc (struct frame_info *frame)
+get_frame_address_in_block (struct frame_info *this_frame)
 {
-  gdb_assert (frame->next != NULL);
-  return frame_pc_unwind (frame->next);
+  return frame_unwind_address_in_block (this_frame->next);
 }
 
 static int
@@ -2010,7 +1346,7 @@ 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));
+    fi->base = frame_base_find_by_frame (fi->next);
   /* 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)
@@ -2026,7 +1362,7 @@ get_frame_locals_address (struct frame_info *fi)
     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));
+    fi->base = frame_base_find_by_frame (fi->next);
   /* 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)
@@ -2044,7 +1380,7 @@ get_frame_args_address (struct frame_info *fi)
     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));
+    fi->base = frame_base_find_by_frame (fi->next);
   /* 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)
@@ -2069,54 +1405,12 @@ frame_relative_level (struct frame_info *fi)
 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;
-
-  /* Some legacy code, e.g, mips_init_extra_frame_info() wants
-     to determine the frame's type prior to it being completely
-     initialized.  Don't attempt to lazily initialize ->unwind for
-     legacy code.  It will be initialized in legacy_get_prev_frame().  */
-  if (frame->unwind == NULL && !legacy_frame_p (current_gdbarch))
-    {
-      /* Initialize the frame's unwinder because it is that which
-         provides the frame's type.  */
-      frame->unwind = frame_unwind_find_by_pc (current_gdbarch,
-                                              get_frame_pc (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 (frame->unwind->type != UNKNOWN_FRAME);
-      frame->type = frame->unwind->type;
-    }
-  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;
+  if (frame->unwind == NULL)
+    /* Initialize the frame's unwinder because that's what
+       provides the frame's type.  */
+    frame->unwind = frame_unwind_find_by_frame (frame->next, 
+                                               &frame->prologue_cache);
+  return frame->unwind->type;
 }
 
 void
@@ -2127,7 +1421,7 @@ deprecated_update_frame_pc_hack (struct frame_info *frame, CORE_ADDR pc)
                        "{ deprecated_update_frame_pc_hack (frame=%d,pc=0x%s) }\n",
                        frame->level, paddr_nz (pc));
   /* NOTE: cagney/2003-03-11: Some architectures (e.g., Arm) are
-     maintaining a locally allocated frame object.  Since such frame's
+     maintaining a locally allocated frame object.  Since such frames
      are not in the frame chain, it isn't possible to assume that the
      frame has a next.  Sigh.  */
   if (frame->next != NULL)
@@ -2151,74 +1445,6 @@ deprecated_update_frame_base_hack (struct frame_info *frame, CORE_ADDR base)
   frame->this_id.value.stack_addr = 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 = FRAME_OBSTACK_ZALLOC (struct frame_info);
-  frame->this_id.p = 1;
-  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)
-    {
-      frame->saved_regs = xcalloc (1, sizeof_saved_regs);
-      make_cleanup (xfree, frame->saved_regs);
-    }
-  if (sizeof_extra_info > 0)
-    {
-      frame->extra_info = xcalloc (1, sizeof_extra_info);
-      make_cleanup (xfree, frame->extra_info);
-    }
-  return frame;
-}
-
 /* Memory access methods.  */
 
 void
@@ -2242,6 +1468,14 @@ get_frame_memory_unsigned (struct frame_info *this_frame, CORE_ADDR addr,
   return read_memory_unsigned_integer (addr, len);
 }
 
+int
+safe_frame_unwind_memory (struct frame_info *this_frame,
+                         CORE_ADDR addr, void *buf, int len)
+{
+  /* NOTE: deprecated_read_memory_nobpt returns zero on success!  */
+  return !deprecated_read_memory_nobpt (addr, buf, len);
+}
+
 /* Architecture method.  */
 
 struct gdbarch *
@@ -2261,12 +1495,12 @@ get_frame_sp (struct frame_info *this_frame)
 CORE_ADDR
 frame_sp_unwind (struct frame_info *next_frame)
 {
-  /* Normality, an architecture that provides a way of obtaining any
+  /* Normality - an architecture that provides a way of obtaining any
      frame inner-most address.  */
   if (gdbarch_unwind_sp_p (current_gdbarch))
     return gdbarch_unwind_sp (current_gdbarch, next_frame);
   /* Things are looking grim.  If it's the inner-most frame and there
-     is a TARGET_READ_SP then that can be used.  */
+     is a TARGET_READ_SP, then that can be used.  */
   if (next_frame->level < 0 && TARGET_READ_SP_P ())
     return TARGET_READ_SP ();
   /* Now things are really are grim.  Hope that the value returned by
@@ -2277,49 +1511,82 @@ frame_sp_unwind (struct frame_info *next_frame)
       frame_unwind_unsigned_register (next_frame, SP_REGNUM, &sp);
       return sp;
     }
-  internal_error (__FILE__, __LINE__, "Missing unwind SP method");
+  internal_error (__FILE__, __LINE__, _("Missing unwind SP method"));
 }
 
+extern initialize_file_ftype _initialize_frame; /* -Wmissing-prototypes */
+
+static struct cmd_list_element *set_backtrace_cmdlist;
+static struct cmd_list_element *show_backtrace_cmdlist;
 
-int
-legacy_frame_p (struct gdbarch *current_gdbarch)
+static void
+set_backtrace_cmd (char *args, int from_tty)
 {
-  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 ());
+  help_list (set_backtrace_cmdlist, "set backtrace ", -1, gdb_stdout);
 }
 
-extern initialize_file_ftype _initialize_frame; /* -Wmissing-prototypes */
+static void
+show_backtrace_cmd (char *args, int from_tty)
+{
+  cmd_show_list (show_backtrace_cmdlist, from_tty, "");
+}
 
 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\
+  observer_attach_target_changed (frame_observer_target_changed);
+
+  add_prefix_cmd ("backtrace", class_maintenance, set_backtrace_cmd, _("\
+Set backtrace specific variables.\n\
+Configure backtrace variables such as the backtrace limit"),
+                 &set_backtrace_cmdlist, "set backtrace ",
+                 0/*allow-unknown*/, &setlist);
+  add_prefix_cmd ("backtrace", class_maintenance, show_backtrace_cmd, _("\
+Show backtrace specific variables\n\
+Show backtrace variables such as the backtrace limit"),
+                 &show_backtrace_cmdlist, "show backtrace ",
+                 0/*allow-unknown*/, &showlist);
+
+  add_setshow_boolean_cmd ("past-main", class_obscure,
+                          &backtrace_past_main, _("\
+Set whether backtraces should continue past \"main\"."), _("\
+Show whether backtraces should continue past \"main\"."), _("\
 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);
-
+of the stack trace."),
+                          NULL, /* FIXME: i18n: Whether backtraces should continue past \"main\" is %s.  */
+                          NULL, NULL, &set_backtrace_cmdlist,
+                          &show_backtrace_cmdlist);
+
+  add_setshow_boolean_cmd ("past-entry", class_obscure,
+                          &backtrace_past_entry, _("\
+Set whether backtraces should continue past the entry point of a program."),
+                          _("\
+Show whether backtraces should continue past the entry point of a program."),
+                          _("\
+Normally there are no callers beyond the entry point of a program, so GDB\n\
+will terminate the backtrace there.  Set this variable if you need to see \n\
+the rest of the stack trace."),
+                          NULL, /* FIXME: i18n: Whether backtraces should continue past the entry point is %s.  */
+                          NULL, NULL, &set_backtrace_cmdlist,
+                          &show_backtrace_cmdlist);
+
+  add_setshow_uinteger_cmd ("limit", class_obscure,
+                           &backtrace_limit, _("\
+Set an upper bound on the number of backtrace levels."), _("\
+Show the upper bound on the number of backtrace levels."), _("\
+No more than the specified number of frames can be displayed or examined.\n\
+Zero is unlimited."),
+                           NULL, /* FIXME: i18n: An upper bound on the number of backtrace levels is %s.  */
+                           NULL, NULL, &set_backtrace_cmdlist,
+                           &show_backtrace_cmdlist);
 
   /* Debug this files internals. */
-  add_show_from_set (add_set_cmd ("frame", class_maintenance, var_zinteger,
-                                 &frame_debug, "Set frame debugging.\n\
+  deprecated_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);
+     &showdebuglist);
 }
This page took 0.047999 seconds and 4 git commands to generate.