Honour PRIVATE keyword
[deliverable/binutils-gdb.git] / gdb / frame.c
index 23fb5b17f6299b3c28ebb280f8615976edde7d12..a032c47e92b1437dc33550c2128d5ea648e4dd4d 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.
 
@@ -65,7 +65,7 @@ struct frame_info
 
   /* The frame's type.  */
   /* FIXME: cagney/2003-04-02: Should instead be returning
-     ->unwind->type.  Unfortunatly, legacy code is still explicitly
+     ->unwind->type.  Unfortunately, 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;
@@ -86,10 +86,6 @@ struct frame_info
      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
@@ -135,16 +131,19 @@ 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_past_main;
+static unsigned int backtrace_limit = UINT_MAX;
 
-static int backtrace_below_main;
 
 void
 fprint_frame_id (struct ui_file *file, struct frame_id id)
 {
-  fprintf_unfiltered (file, "{stack=0x%s,code=0x%s}",
+  fprintf_unfiltered (file, "{stack=0x%s,code=0x%s,special=0x%s}",
                      paddr_nz (id.stack_addr),
-                     paddr_nz (id.code_addr));
+                     paddr_nz (id.code_addr),
+                     paddr_nz (id.special_addr));
 }
 
 static void
@@ -229,14 +228,12 @@ get_frame_id (struct frame_info *fi)
       /* Find the unwinder.  */
       if (fi->unwind == NULL)
        {
-         fi->unwind = frame_unwind_find_by_pc (current_gdbarch,
-                                               get_frame_pc (fi));
+         fi->unwind = frame_unwind_find_by_frame (fi->next);
          /* 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
+            directly.  Unfortunately, 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;
        }
       /* Find THIS frame's ID.  */
@@ -255,14 +252,22 @@ get_frame_id (struct frame_info *fi)
 const struct frame_id null_frame_id; /* All zeros.  */
 
 struct frame_id
-frame_id_build (CORE_ADDR stack_addr, CORE_ADDR code_addr)
+frame_id_build_special (CORE_ADDR stack_addr, CORE_ADDR code_addr,
+                        CORE_ADDR special_addr)
 {
   struct frame_id id;
   id.stack_addr = stack_addr;
   id.code_addr = code_addr;
+  id.special_addr = special_addr;
   return id;
 }
 
+struct frame_id
+frame_id_build (CORE_ADDR stack_addr, CORE_ADDR code_addr)
+{
+  return frame_id_build_special (stack_addr, code_addr, 0);
+}
+
 int
 frame_id_p (struct frame_id l)
 {
@@ -291,8 +296,14 @@ frame_id_eq (struct frame_id l, struct frame_id r)
   else if (l.code_addr == 0 || r.code_addr == 0)
     /* A zero code addr is a wild card, 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.code_addr != r.code_addr)
+    /* If .code addresses are different, the frames are different.  */
+    eq = 0;
+  else if (l.special_addr == 0 || r.special_addr == 0)
+    /* A zero special addr is a wild card (or unused), always succeed.  */
+    eq = 1;
+  else if (l.special_addr == r.special_addr)
+    /* Frames are equal.  */
     eq = 1;
   else
     /* No luck.  */
@@ -319,7 +330,7 @@ frame_id_inner (struct frame_id l, struct frame_id r)
     /* Only return non-zero when strictly inner than.  Note that, per
        comment in "frame.h", there is some fuzz here.  Frameless
        functions are not strictly inner than (same .stack but
-       different .code).  */
+       different .code and/or .special address).  */
     inner = INNER_THAN (l.stack_addr, r.stack_addr);
   if (frame_debug)
     {
@@ -422,8 +433,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",
@@ -473,7 +487,7 @@ frame_pop (struct frame_info *this_frame)
          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
+         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.
@@ -495,9 +509,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 (frame, 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
@@ -517,14 +532,12 @@ frame_register_unwind (struct frame_info *frame, int regnum,
   /* Find the unwinder.  */
   if (frame->unwind == NULL)
     {
-      frame->unwind = frame_unwind_find_by_pc (current_gdbarch,
-                                              get_frame_pc (frame));
+      frame->unwind = frame_unwind_find_by_frame (frame->next);
       /* 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
+        directly.  Unfortunately, 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;
     }
 
@@ -626,7 +639,7 @@ frame_unwind_register_signed (struct frame_info *frame, int regnum)
 {
   char buf[MAX_REGISTER_SIZE];
   frame_unwind_register (frame, regnum, buf);
-  return extract_signed_integer (buf, REGISTER_VIRTUAL_SIZE (regnum));
+  return extract_signed_integer (buf, DEPRECATED_REGISTER_VIRTUAL_SIZE (regnum));
 }
 
 LONGEST
@@ -640,7 +653,7 @@ 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_VIRTUAL_SIZE (regnum));
+  return extract_unsigned_integer (buf, DEPRECATED_REGISTER_VIRTUAL_SIZE (regnum));
 }
 
 ULONGEST
@@ -649,63 +662,13 @@ get_frame_register_unsigned (struct frame_info *frame, int regnum)
   return frame_unwind_register_unsigned (frame->next, regnum);
 }
 
-void
-frame_unwind_signed_register (struct frame_info *frame, int regnum,
-                             LONGEST *val)
-{
-  char buf[MAX_REGISTER_SIZE];
-  frame_unwind_register (frame, regnum, buf);
-  (*val) = extract_signed_integer (buf, REGISTER_VIRTUAL_SIZE (regnum));
-}
-
 void
 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_VIRTUAL_SIZE (regnum));
-}
-
-void
-frame_read_register (struct frame_info *frame, int regnum, void *buf)
-{
-  gdb_assert (frame != NULL && frame->next != NULL);
-  frame_unwind_register (frame->next, regnum, buf);
-}
-
-void
-frame_read_unsigned_register (struct frame_info *frame, int regnum,
-                             ULONGEST *val)
-{
-  /* 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);
-}
-
-void
-frame_read_signed_register (struct frame_info *frame, int regnum,
-                           LONGEST *val)
-{
-  /* See note above in frame_read_unsigned_register().  */
-  gdb_assert (frame != NULL && frame->next != NULL);
-  frame_unwind_signed_register (frame->next, regnum, val);
+  (*val) = extract_unsigned_integer (buf, DEPRECATED_REGISTER_VIRTUAL_SIZE (regnum));
 }
 
 void
@@ -741,7 +704,8 @@ put_frame_register (struct frame_info *frame, int regnum, const void *buf)
 /* 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 DEPRECATED_REGISTER_RAW_SIZE
+   (REGNUM).
 
    Returns 0 if the register value could not be found.  */
 
@@ -841,7 +805,7 @@ frame_saved_regs_zalloc (struct frame_info *fi)
 }
 
 CORE_ADDR *
-get_frame_saved_regs (struct frame_info *fi)
+deprecated_get_frame_saved_regs (struct frame_info *fi)
 {
   return fi->saved_regs;
 }
@@ -914,12 +878,24 @@ get_selected_frame (void)
   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 ();
+}
+
 /* 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
@@ -940,7 +916,13 @@ select_frame (struct frame_info *fi)
      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
@@ -963,7 +945,7 @@ legacy_saved_regs_prev_register (struct frame_info *next_frame,
                                 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
+     Unfortunately, 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.
 
@@ -971,16 +953,16 @@ legacy_saved_regs_prev_register (struct frame_info *next_frame,
   struct frame_info *frame = next_frame->prev;
   gdb_assert (frame != NULL);
 
-  if (get_frame_saved_regs (frame) == NULL)
+  if (deprecated_get_frame_saved_regs (frame) == NULL)
     {
       /* If nothing's initialized the saved regs, do it now.  */
       gdb_assert (DEPRECATED_FRAME_INIT_SAVED_REGS_P ());
       DEPRECATED_FRAME_INIT_SAVED_REGS (frame);
-      gdb_assert (get_frame_saved_regs (frame) != NULL);
+      gdb_assert (deprecated_get_frame_saved_regs (frame) != NULL);
     }
 
-  if (get_frame_saved_regs (frame) != NULL
-      && get_frame_saved_regs (frame)[regnum] != 0)
+  if (deprecated_get_frame_saved_regs (frame) != NULL
+      && deprecated_get_frame_saved_regs (frame)[regnum] != 0)
     {
       if (regnum == SP_REGNUM)
        {
@@ -992,8 +974,8 @@ legacy_saved_regs_prev_register (struct frame_info *next_frame,
          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]);
+           store_unsigned_integer (bufferp, DEPRECATED_REGISTER_RAW_SIZE (regnum),
+                                   deprecated_get_frame_saved_regs (frame)[regnum]);
        }
       else
        {
@@ -1001,7 +983,7 @@ legacy_saved_regs_prev_register (struct frame_info *next_frame,
              a local copy of its value.  */
          *optimizedp = 0;
          *lvalp = lval_memory;
-         *addrp = get_frame_saved_regs (frame)[regnum];
+         *addrp = deprecated_get_frame_saved_regs (frame)[regnum];
          *realnump = -1;
          if (bufferp != NULL)
            {
@@ -1019,15 +1001,15 @@ legacy_saved_regs_prev_register (struct frame_info *next_frame,
              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));
+                   = frame_obstack_zalloc (DEPRECATED_REGISTER_RAW_SIZE (regnum));
+                 read_memory (deprecated_get_frame_saved_regs (frame)[regnum], regs[regnum],
+                              DEPRECATED_REGISTER_RAW_SIZE (regnum));
                }
-             memcpy (bufferp, regs[regnum], REGISTER_RAW_SIZE (regnum));
+             memcpy (bufferp, regs[regnum], DEPRECATED_REGISTER_RAW_SIZE (regnum));
 #else
              /* Read the value in from memory.  */
-             read_memory (get_frame_saved_regs (frame)[regnum], bufferp,
-                          REGISTER_RAW_SIZE (regnum));
+             read_memory (deprecated_get_frame_saved_regs (frame)[regnum], bufferp,
+                          DEPRECATED_REGISTER_RAW_SIZE (regnum));
 #endif
            }
        }
@@ -1046,9 +1028,12 @@ 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");
+  /* A developer is trying to bring up a new architecture, help them
+     by providing a default unwinder that refuses to unwind anything
+     (the ID is always NULL).  In the case of legacy code,
+     legacy_get_prev_frame() will have previously set ->this_id.p, so
+     this code won't be called.  */
+  (*id) = null_frame_id;
 }
        
 const struct frame_unwind legacy_saved_regs_unwinder = {
@@ -1074,9 +1059,9 @@ const struct frame_unwind *legacy_saved_regs_unwind = &legacy_saved_regs_unwinde
    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.
+   Set *ADDRP to the address, either in memory or as a
+   DEPRECATED_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.  */
 
@@ -1124,8 +1109,8 @@ deprecated_generic_get_saved_register (char *raw_buffer, int *optimized,
            }
 
          DEPRECATED_FRAME_INIT_SAVED_REGS (frame);
-         if (get_frame_saved_regs (frame) != NULL
-             && get_frame_saved_regs (frame)[regnum] != 0)
+         if (deprecated_get_frame_saved_regs (frame) != NULL
+             && deprecated_get_frame_saved_regs (frame)[regnum] != 0)
            {
              if (lval)         /* found it saved on the stack */
                *lval = lval_memory;
@@ -1135,16 +1120,16 @@ deprecated_generic_get_saved_register (char *raw_buffer, int *optimized,
                    /* 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]);
+                                           DEPRECATED_REGISTER_RAW_SIZE (regnum),
+                                           deprecated_get_frame_saved_regs (frame)[regnum]);
                }
              else
                {
                  if (addrp)    /* any other register */
-                   *addrp = get_frame_saved_regs (frame)[regnum];
+                   *addrp = deprecated_get_frame_saved_regs (frame)[regnum];
                  if (raw_buffer)
-                   read_memory (get_frame_saved_regs (frame)[regnum], raw_buffer,
-                                REGISTER_RAW_SIZE (regnum));
+                   read_memory (deprecated_get_frame_saved_regs (frame)[regnum], raw_buffer,
+                                DEPRECATED_REGISTER_RAW_SIZE (regnum));
                }
              return;
            }
@@ -1157,7 +1142,7 @@ deprecated_generic_get_saved_register (char *raw_buffer, int *optimized,
   if (lval)                    /* found it in a live register */
     *lval = lval_register;
   if (addrp)
-    *addrp = REGISTER_BYTE (regnum);
+    *addrp = DEPRECATED_REGISTER_BYTE (regnum);
   if (raw_buffer)
     deprecated_read_register_gen (regnum, raw_buffer);
 }
@@ -1206,7 +1191,7 @@ 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);
+  fi->unwind = frame_unwind_find_by_frame (fi->next);
   if (fi->unwind->type != UNKNOWN_FRAME)
     fi->type = fi->unwind->type;
   else
@@ -1242,12 +1227,6 @@ get_next_frame (struct frame_info *this_frame)
     return NULL;
 }
 
-struct frame_info *
-deprecated_get_next_frame_hack (struct frame_info *this_frame)
-{
-  return this_frame->next;
-}
-
 /* Flush the entire frame cache.  */
 
 void
@@ -1301,7 +1280,7 @@ legacy_get_prev_frame (struct frame_info *this_frame)
   prev = FRAME_OBSTACK_ZALLOC (struct frame_info);
   prev->level = this_frame->level + 1;
 
-  /* Do not completly wire it in to the frame chain.  Some (bad) code
+  /* Do not completely 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).
@@ -1319,7 +1298,7 @@ legacy_get_prev_frame (struct frame_info *this_frame)
      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
+     Unfortunately 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;
@@ -1365,8 +1344,7 @@ legacy_get_prev_frame (struct frame_info *this_frame)
 
       /* 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));
+      prev->unwind = frame_unwind_find_by_frame (prev->next);
       if (prev->unwind->type == UNKNOWN_FRAME)
        prev->type = frame_type_from_pc (get_frame_pc (prev));
       else
@@ -1430,7 +1408,7 @@ legacy_get_prev_frame (struct frame_info *this_frame)
       /* FIXME: cagney/2002-01-19: This call will go away.  Instead of
         initializing extra info, all frames will use the frame_cache
         (passed to the unwind functions) to store additional frame
-        info.  Unfortunatly legacy targets can't use
+        info.  Unfortunately 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
@@ -1471,7 +1449,8 @@ legacy_get_prev_frame (struct frame_info *this_frame)
        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);
+    fromleaf = (DEPRECATED_FRAMELESS_FUNCTION_INVOCATION_P ()
+               && DEPRECATED_FRAMELESS_FUNCTION_INVOCATION (this_frame));
   else
     fromleaf = 0;
 
@@ -1514,11 +1493,10 @@ legacy_get_prev_frame (struct frame_info *this_frame)
              to the new frame code.  Implement FRAME_CHAIN the way the
              new frame will.  */
          /* Find PREV frame's unwinder.  */
-         prev->unwind = frame_unwind_find_by_pc (current_gdbarch,
-                                                 frame_pc_unwind (this_frame));
+         prev->unwind = frame_unwind_find_by_frame (this_frame->next);
          /* 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
+            directly.  Unfortunately, legacy code, called by
             legacy_get_prev_frame, explicitly set the frames type
             using the method deprecated_set_frame_type().  */
          prev->type = prev->unwind->type;
@@ -1676,8 +1654,7 @@ legacy_get_prev_frame (struct frame_info *this_frame)
      If there isn't a FRAME_CHAIN, the code above will have already
      done this.  */
   if (prev->unwind == NULL)
-    prev->unwind = frame_unwind_find_by_pc (current_gdbarch,
-                                           get_frame_pc (prev));
+    prev->unwind = frame_unwind_find_by_frame (prev->next);
 
   /* If the unwinder provides a frame type, use it.  Otherwize
      continue on to that heuristic mess.  */
@@ -1746,7 +1723,12 @@ legacy_get_prev_frame (struct frame_info *this_frame)
 
 /* Return a structure containing various interesting information
    about the frame that called THIS_FRAME.  Returns NULL
-   if there is no such frame.  */
+   if there is no such frame.
+
+   This function tests some target-independent conditions that should
+   terminate the frame chain, such as unwinding past main().  It
+   should not contain any target-dependent tests, such as checking
+   whether the program-counter is zero.  */
 
 struct frame_info *
 get_prev_frame (struct frame_info *this_frame)
@@ -1803,9 +1785,13 @@ get_prev_frame (struct frame_info *this_frame)
      get_current_frame().  */
   gdb_assert (this_frame != NULL);
 
+  /* Make sure we pass an address within THIS_FRAME's code block to
+     inside_main_func.  Otherwise, we might stop unwinding at a
+     function which has a call instruction as its last instruction if
+     that function immediately precedes main().  */
   if (this_frame->level >= 0
-      && !backtrace_below_main
-      && inside_main_func (get_frame_pc (this_frame)))
+      && !backtrace_past_main
+      && inside_main_func (get_frame_address_in_block (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
@@ -1816,6 +1802,50 @@ get_prev_frame (struct frame_info *this_frame)
       return NULL;
     }
 
+  if (this_frame->level > backtrace_limit)
+    {
+      error ("Backtrace limit of %d exceeded", backtrace_limit);
+    }
+
+  /* If we're already inside the entry function for the main objfile,
+     then it isn't valid.  Don't apply this test to a dummy frame -
+     dummy frame PC's typically land in the entry func.  Don't apply
+     this test to the sentinel frame.  Sentinel frames should always
+     be allowed to unwind.  */
+  /* NOTE: cagney/2003-02-25: Don't enable until someone has found
+     hard evidence that this is needed.  */
+  /* 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 wierd and wonderful ways somewhere inside the entry
+     file.  Suspect that deprecated_inside_entry_file and
+     inside_entry_func tests 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: cagney/2003-07-15: Need to add a "set backtrace
+     beyond-entry-func" command so that this can be selectively
+     disabled.  */
+  if (0
+#if 0
+      && backtrace_beyond_entry_func
+#endif
+      && this_frame->type != 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, "// inside entry func }\n");
+       }
+      return NULL;
+    }
+
   /* Only try to do the unwind once.  */
   if (this_frame->prev_p)
     {
@@ -1829,7 +1859,6 @@ get_prev_frame (struct frame_info *this_frame)
     }
   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.
@@ -1841,44 +1870,25 @@ get_prev_frame (struct frame_info *this_frame)
   /* NOTE: cagney/2003-01-10: If there is a way of disabling this test
      then it should probably be moved to before the ->prev_p test,
      above.  */
-  /* NOTE: vinschen/2003-04-01: Disabled.  It turns out that the call to
-     inside_entry_file destroys a meaningful backtrace under some
-     conditions.  E. g. the backtrace tests in the asm-source testcase
-     are broken for some targets.  In this test the functions are all
-     implemented as part of one file and the testcase is not necessarily
-     linked with a start file (depending on the target).  What happens is,
-     that the first frame is printed normaly and following frames are
-     treated as being inside the enttry file then.  This way, only the
-     #0 frame is printed in the backtrace output.  */
-  if (this_frame->type != DUMMY_FRAME && this_frame->level >= 0
-      && inside_entry_file (get_frame_pc (this_frame)))
-    {
-      if (frame_debug)
-       {
-         fprintf_unfiltered (gdb_stdlog, "-> ");
-         fprint_frame (gdb_stdlog, NULL);
-         fprintf_unfiltered (gdb_stdlog, " // inside entry file }\n");
-       }
-      return NULL;
-    }
-#endif
-
-  /* If we're already inside the entry function for the main objfile,
-     then it isn't valid.  Don't apply this test to a dummy frame -
-     dummy frame PC's typically land in the entry func.  Don't apply
-     this test to the sentinel frame.  Sentinel frames should always
-     be allowed to unwind.  */
-  /* NOTE: cagney/2003-02-25: Don't enable until someone has found
-     hard evidence that this is needed.  */
+  /* NOTE: vinschen/2003-04-01: Disabled.  It turns out that the call
+     to deprecated_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 (0
       && this_frame->type != DUMMY_FRAME && this_frame->level >= 0
-      && inside_entry_func (get_frame_pc (this_frame)))
+      && deprecated_inside_entry_file (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");
+         fprintf_unfiltered (gdb_stdlog, " // inside entry file }\n");
        }
       return NULL;
     }
@@ -1935,37 +1945,6 @@ get_prev_frame (struct frame_info *this_frame)
   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)
-    {
-      /* 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");
-       }
-      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.  */
@@ -2006,6 +1985,33 @@ get_frame_pc (struct frame_info *frame)
   return frame_pc_unwind (frame->next);
 }
 
+/* Return an address of that falls within the frame's code block.  */
+
+CORE_ADDR
+frame_unwind_address_in_block (struct frame_info *next_frame)
+{
+  /* A draft address.  */
+  CORE_ADDR pc = frame_pc_unwind (next_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_address_in_block (struct frame_info *this_frame)
+{
+  return frame_unwind_address_in_block (this_frame->next);
+}
+
 static int
 pc_notcurrent (struct frame_info *frame)
 {
@@ -2045,7 +2051,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)
@@ -2061,7 +2067,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)
@@ -2079,7 +2085,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)
@@ -2118,14 +2124,12 @@ get_frame_type (struct frame_info *frame)
     {
       /* 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));
+      frame->unwind = frame_unwind_find_by_frame (frame->next);
       /* 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
+        directly.  Unfortunately, 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)
@@ -2186,60 +2190,13 @@ 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 ();
+  struct frame_info *frame = XMALLOC (struct frame_info);
+  memset (frame, 0, sizeof (*frame));
+  frame->this_id.p = 1;
   make_cleanup (xfree, frame);
   if (sizeof_saved_regs > 0)
     {
@@ -2319,27 +2276,65 @@ frame_sp_unwind (struct frame_info *next_frame)
 int
 legacy_frame_p (struct gdbarch *current_gdbarch)
 {
-  return (DEPRECATED_INIT_FRAME_PC_P ()
-         || DEPRECATED_INIT_FRAME_PC_FIRST_P ()
-         || DEPRECATED_INIT_EXTRA_FRAME_INFO_P ()
-         || DEPRECATED_FRAME_CHAIN_P ()
-         || !gdbarch_unwind_dummy_id_p (current_gdbarch));
+  if (DEPRECATED_INIT_FRAME_PC_P ()
+      || DEPRECATED_INIT_FRAME_PC_FIRST_P ()
+      || DEPRECATED_INIT_EXTRA_FRAME_INFO_P ()
+      || DEPRECATED_FRAME_CHAIN_P ())
+    /* No question, it's a legacy frame.  */
+    return 1;
+  if (gdbarch_unwind_dummy_id_p (current_gdbarch))
+    /* No question, it's not a legacy frame (provided none of the
+       deprecated methods checked above are present that is).  */
+    return 0;
+  if (DEPRECATED_TARGET_READ_FP_P ()
+      || DEPRECATED_FP_REGNUM >= 0)
+    /* Assume it's legacy.  If you're trying to convert a legacy frame
+       target to the new mechanism, get rid of these.  legacy
+       get_prev_frame requires these when unwind_frame_id isn't
+       available.  */
+    return 1;
+  /* Default to assuming that it's brand new code, and hence not
+     legacy.  Force it down the non-legacy path so that the new code
+     uses the new frame mechanism from day one.  Dummy frame's won't
+     work very well but we can live with that.  */
+  return 0;
 }
 
 extern initialize_file_ftype _initialize_frame; /* -Wmissing-prototypes */
 
+static struct cmd_list_element *set_backtrace_cmdlist;
+static struct cmd_list_element *show_backtrace_cmdlist;
+
+static void
+set_backtrace_cmd (char *args, int from_tty)
+{
+  help_list (set_backtrace_cmdlist, "set backtrace ", -1, gdb_stdout);
+}
+
+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, "\
+  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\".\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\
@@ -2348,8 +2343,17 @@ 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);
-
+                          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.\n\
+No more than the specified number of frames can be displayed or examined.\n\
+Zero is unlimited.", "\
+Show the upper bound on the number of backtrace levels.",
+                           NULL, NULL, &set_backtrace_cmdlist,
+                           &show_backtrace_cmdlist);
 
   /* Debug this files internals. */
   add_show_from_set (add_set_cmd ("frame", class_maintenance, var_zinteger,
This page took 0.036098 seconds and 4 git commands to generate.