gdb: fix vfork with multiple threads
[deliverable/binutils-gdb.git] / gdb / frame.c
index 15168fb4315924a5536e01f3eb25a76f6dbffb91..3f2d2700541ce3f2388a9afb7b30bece54e4b286 100644 (file)
@@ -1,6 +1,6 @@
 /* Cache and manage frames for GDB, the GNU debugger.
 
-   Copyright (C) 1986-2020 Free Software Foundation, Inc.
+   Copyright (C) 1986-2021 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -111,6 +111,9 @@ enum class frame_id_status
 
 struct frame_info
 {
+  /* Return a string representation of this frame.  */
+  std::string to_string () const;
+
   /* Level of this frame.  The inner-most (youngest) frame is at level
      0.  As you move towards the outer-most (oldest) frame, the level
      increases.  This is a cached value.  It could just as easily be
@@ -317,22 +320,21 @@ frame_stash_invalidate (void)
 /* See frame.h  */
 scoped_restore_selected_frame::scoped_restore_selected_frame ()
 {
-  m_fid = get_frame_id (get_selected_frame (NULL));
+  m_lang = current_language->la_language;
+  save_selected_frame (&m_fid, &m_level);
 }
 
 /* See frame.h  */
 scoped_restore_selected_frame::~scoped_restore_selected_frame ()
 {
-  frame_info *frame = frame_find_by_id (m_fid);
-  if (frame == NULL)
-    warning (_("Unable to restore previously selected frame."));
-  else
-    select_frame (frame);
+  restore_selected_frame (m_fid, m_level);
+  set_language (m_lang);
 }
 
 /* Flag to control debugging.  */
 
-unsigned int frame_debug;
+bool frame_debug;
+
 static void
 show_frame_debug (struct ui_file *file, int from_tty,
                  struct cmd_list_element *c, const char *value)
@@ -375,134 +377,125 @@ show_backtrace_limit (struct ui_file *file, int from_tty,
                    value);
 }
 
+/* See frame.h.  */
 
-static void
-fprint_field (struct ui_file *file, const char *name, int p, CORE_ADDR addr)
+std::string
+frame_id::to_string () const
 {
-  if (p)
-    fprintf_unfiltered (file, "%s=%s", name, hex_string (addr));
-  else
-    fprintf_unfiltered (file, "!%s", name);
-}
+  const struct frame_id &id = *this;
 
-void
-fprint_frame_id (struct ui_file *file, struct frame_id id)
-{
-  fprintf_unfiltered (file, "{");
+  std::string res = "{";
 
   if (id.stack_status == FID_STACK_INVALID)
-    fprintf_unfiltered (file, "!stack");
+    res += "!stack";
   else if (id.stack_status == FID_STACK_UNAVAILABLE)
-    fprintf_unfiltered (file, "stack=<unavailable>");
+    res += "stack=<unavailable>";
   else if (id.stack_status == FID_STACK_SENTINEL)
-    fprintf_unfiltered (file, "stack=<sentinel>");
+    res += "stack=<sentinel>";
   else if (id.stack_status == FID_STACK_OUTER)
-    fprintf_unfiltered (file, "stack=<outer>");
+    res += "stack=<outer>";
   else
-    fprintf_unfiltered (file, "stack=%s", hex_string (id.stack_addr));
+    res += std::string ("stack=") + hex_string (id.stack_addr);
 
-  fprintf_unfiltered (file, ",");
-
-  fprint_field (file, "code", id.code_addr_p, id.code_addr);
-  fprintf_unfiltered (file, ",");
+  /* Helper function to format 'N=A' if P is true, otherwise '!N'.  */
+  auto field_to_string = [] (const char *n, bool p, CORE_ADDR a) -> std::string
+  {
+    if (p)
+      return std::string (n) + "=" + core_addr_to_string (a);
+    else
+      return std::string ("!") + std::string (n);
+  };
 
-  fprint_field (file, "special", id.special_addr_p, id.special_addr);
+  res += (std::string (",")
+         + field_to_string ("code", id.code_addr_p, id.code_addr)
+         + std::string (",")
+         + field_to_string ("special", id.special_addr_p, id.special_addr));
 
   if (id.artificial_depth)
-    fprintf_unfiltered (file, ",artificial=%d", id.artificial_depth);
-
-  fprintf_unfiltered (file, "}");
+    res += ",artificial=" + std::to_string (id.artificial_depth);
+  res += "}";
+  return res;
 }
 
-static void
-fprint_frame_type (struct ui_file *file, enum frame_type type)
+/* Return a string representation of TYPE.  */
+
+static const char *
+frame_type_str (frame_type type)
 {
   switch (type)
     {
     case NORMAL_FRAME:
-      fprintf_unfiltered (file, "NORMAL_FRAME");
-      return;
+      return "NORMAL_FRAME";
+
     case DUMMY_FRAME:
-      fprintf_unfiltered (file, "DUMMY_FRAME");
-      return;
+      return "DUMMY_FRAME";
+
     case INLINE_FRAME:
-      fprintf_unfiltered (file, "INLINE_FRAME");
-      return;
+      return "INLINE_FRAME";
+
     case TAILCALL_FRAME:
-      fprintf_unfiltered (file, "TAILCALL_FRAME");
-      return;
+      return "TAILCALL_FRAME";
+
     case SIGTRAMP_FRAME:
-      fprintf_unfiltered (file, "SIGTRAMP_FRAME");
-      return;
+      return "SIGTRAMP_FRAME";
+
     case ARCH_FRAME:
-      fprintf_unfiltered (file, "ARCH_FRAME");
-      return;
+      return "ARCH_FRAME";
+
     case SENTINEL_FRAME:
-      fprintf_unfiltered (file, "SENTINEL_FRAME");
-      return;
+      return "SENTINEL_FRAME";
+
     default:
-      fprintf_unfiltered (file, "<unknown type>");
-      return;
+      return "<unknown type>";
     };
 }
 
-static void
-fprint_frame (struct ui_file *file, struct frame_info *fi)
+ /* See struct frame_info.  */
+
+std::string
+frame_info::to_string () const
 {
-  if (fi == NULL)
-    {
-      fprintf_unfiltered (file, "<NULL frame>");
-      return;
-    }
+  const frame_info *fi = this;
 
-  fprintf_unfiltered (file, "{");
-  fprintf_unfiltered (file, "level=%d", fi->level);
-  fprintf_unfiltered (file, ",");
+  std::string res;
+
+  res += string_printf ("{level=%d,", fi->level);
 
-  fprintf_unfiltered (file, "type=");
   if (fi->unwind != NULL)
-    fprint_frame_type (file, fi->unwind->type);
+    res += string_printf ("type=%s,", frame_type_str (fi->unwind->type));
   else
-    fprintf_unfiltered (file, "<unknown>");
-  fprintf_unfiltered (file, ",");
+    res += "type=<unknown>,";
 
-  fprintf_unfiltered (file, "unwind=");
   if (fi->unwind != NULL)
-    gdb_print_host_address (fi->unwind, file);
+    res += string_printf ("unwind=%p,", host_address_to_string (fi->unwind));
   else
-    fprintf_unfiltered (file, "<unknown>");
-  fprintf_unfiltered (file, ",");
+    res += "unwind=<unknown>,";
 
-  fprintf_unfiltered (file, "pc=");
   if (fi->next == NULL || fi->next->prev_pc.status == CC_UNKNOWN)
-    fprintf_unfiltered (file, "<unknown>");
+    res += "pc=<unknown>,";
   else if (fi->next->prev_pc.status == CC_VALUE)
-    {
-      fprintf_unfiltered (file, "%s", hex_string (fi->next->prev_pc.value));
-      if (fi->next->prev_pc.masked)
-       fprintf_unfiltered (file, "[PAC]");
-    }
+    res += string_printf ("pc=%s%s,", hex_string (fi->next->prev_pc.value),
+                         fi->next->prev_pc.masked ? "[PAC]" : "");
   else if (fi->next->prev_pc.status == CC_NOT_SAVED)
-    val_print_not_saved (file);
+    res += "pc=<not saved>,";
   else if (fi->next->prev_pc.status == CC_UNAVAILABLE)
-    val_print_unavailable (file);
-  fprintf_unfiltered (file, ",");
+    res += "pc=<unavailable>,";
 
-  fprintf_unfiltered (file, "id=");
   if (fi->this_id.p == frame_id_status::NOT_COMPUTED)
-    fprintf_unfiltered (file, "<not computed>");
+    res += "id=<not computed>,";
   else if (fi->this_id.p == frame_id_status::COMPUTING)
-    fprintf_unfiltered (file, "<computing>");
+    res += "id=<computing>,";
   else
-    fprint_frame_id (file, fi->this_id.value);
-  fprintf_unfiltered (file, ",");
+    res += string_printf ("id=%s,", fi->this_id.value.to_string ().c_str ());
 
-  fprintf_unfiltered (file, "func=");
   if (fi->next != NULL && fi->next->prev_func.status == CC_VALUE)
-    fprintf_unfiltered (file, "%s", hex_string (fi->next->prev_func.addr));
+    res += string_printf ("func=%s", hex_string (fi->next->prev_func.addr));
   else
-    fprintf_unfiltered (file, "<unknown>");
-  fprintf_unfiltered (file, "}");
+    res += "func=<unknown>";
+
+  res += "}";
+
+  return res;
 }
 
 /* Given FRAME, return the enclosing frame as found in real frames read-in from
@@ -567,6 +560,8 @@ skip_tailcall_frames (struct frame_info *frame)
 static void
 compute_frame_id (struct frame_info *fi)
 {
+  FRAME_SCOPED_DEBUG_ENTER_EXIT;
+
   gdb_assert (fi->this_id.p == frame_id_status::NOT_COMPUTED);
 
   unsigned int entry_generation = get_frame_cache_generation ();
@@ -576,9 +571,7 @@ compute_frame_id (struct frame_info *fi)
       /* Mark this frame's id as "being computed.  */
       fi->this_id.p = frame_id_status::COMPUTING;
 
-      if (frame_debug)
-       fprintf_unfiltered (gdb_stdlog, "{ compute_frame_id (fi=%d) ",
-                           fi->level);
+      frame_debug_printf ("fi=%d", fi->level);
 
       /* Find the unwinder.  */
       if (fi->unwind == NULL)
@@ -593,17 +586,12 @@ compute_frame_id (struct frame_info *fi)
       /* Mark this frame's id as "computed".  */
       fi->this_id.p = frame_id_status::COMPUTED;
 
-      if (frame_debug)
-       {
-         fprintf_unfiltered (gdb_stdlog, "-> ");
-         fprint_frame_id (gdb_stdlog, fi->this_id.value);
-         fprintf_unfiltered (gdb_stdlog, " }\n");
-       }
+      frame_debug_printf ("  -> %s", fi->this_id.value.to_string ().c_str ());
     }
   catch (const gdb_exception &ex)
     {
       /* On error, revert the frame id status to not computed.  If the frame
-         cache generation changed, the frame object doesn't exist anymore, so
+        cache generation changed, the frame object doesn't exist anymore, so
         don't touch it.  */
       if (get_frame_cache_generation () == entry_generation)
        fi->this_id.p = frame_id_status::NOT_COMPUTED;
@@ -679,7 +667,7 @@ const struct frame_id outer_frame_id = { 0, 0, 0, FID_STACK_OUTER, 0, 1, 0 };
 
 struct frame_id
 frame_id_build_special (CORE_ADDR stack_addr, CORE_ADDR code_addr,
-                        CORE_ADDR special_addr)
+                       CORE_ADDR special_addr)
 {
   struct frame_id id = null_frame_id;
 
@@ -749,12 +737,7 @@ frame_id_p (frame_id l)
   /* The frame is valid iff it has a valid stack address.  */
   bool p = l.stack_status != FID_STACK_INVALID;
 
-  if (frame_debug)
-    {
-      fprintf_unfiltered (gdb_stdlog, "{ frame_id_p (l=");
-      fprint_frame_id (gdb_stdlog, l);
-      fprintf_unfiltered (gdb_stdlog, ") -> %d }\n", p);
-    }
+  frame_debug_printf ("l=%s -> %d", l.to_string ().c_str (), p);
 
   return p;
 }
@@ -797,14 +780,8 @@ frame_id_eq (frame_id l, frame_id r)
     /* Frames are equal.  */
     eq = true;
 
-  if (frame_debug)
-    {
-      fprintf_unfiltered (gdb_stdlog, "{ frame_id_eq (l=");
-      fprint_frame_id (gdb_stdlog, l);
-      fprintf_unfiltered (gdb_stdlog, ",r=");
-      fprint_frame_id (gdb_stdlog, r);
-      fprintf_unfiltered (gdb_stdlog, ") -> %d }\n", eq);
-    }
+  frame_debug_printf ("l=%s, r=%s -> %d",
+                     l.to_string ().c_str (), r.to_string ().c_str (), eq);
 
   return eq;
 }
@@ -880,14 +857,9 @@ frame_id_inner (struct gdbarch *gdbarch, struct frame_id l, struct frame_id r)
        different .code and/or .special address).  */
     inner = gdbarch_inner_than (gdbarch, l.stack_addr, r.stack_addr);
 
-  if (frame_debug)
-    {
-      fprintf_unfiltered (gdb_stdlog, "{ frame_id_inner (l=");
-      fprint_frame_id (gdb_stdlog, l);
-      fprintf_unfiltered (gdb_stdlog, ",r=");
-      fprint_frame_id (gdb_stdlog, r);
-      fprintf_unfiltered (gdb_stdlog, ") -> %d }\n", inner);
-    }
+  frame_debug_printf ("is l=%s inner than r=%s? %d",
+                     l.to_string ().c_str (), r.to_string ().c_str (),
+                     inner);
 
   return inner;
 }
@@ -982,21 +954,15 @@ frame_unwind_pc (struct frame_info *this_frame)
            {
              this_frame->prev_pc.status = CC_UNAVAILABLE;
 
-             if (frame_debug)
-               fprintf_unfiltered (gdb_stdlog,
-                                   "{ frame_unwind_pc (this_frame=%d)"
-                                   " -> <unavailable> }\n",
-                                   this_frame->level);
+             frame_debug_printf ("this_frame=%d -> <unavailable>",
+                                 this_frame->level);
            }
          else if (ex.error == OPTIMIZED_OUT_ERROR)
            {
              this_frame->prev_pc.status = CC_NOT_SAVED;
 
-             if (frame_debug)
-               fprintf_unfiltered (gdb_stdlog,
-                                   "{ frame_unwind_pc (this_frame=%d)"
-                                   " -> <not saved> }\n",
-                                   this_frame->level);
+             frame_debug_printf ("this_frame=%d -> <not saved>",
+                                 this_frame->level);
            }
          else
            throw;
@@ -1006,12 +972,10 @@ frame_unwind_pc (struct frame_info *this_frame)
        {
          this_frame->prev_pc.value = pc;
          this_frame->prev_pc.status = CC_VALUE;
-         if (frame_debug)
-           fprintf_unfiltered (gdb_stdlog,
-                               "{ frame_unwind_pc (this_frame=%d) "
-                               "-> %s }\n",
-                               this_frame->level,
-                               hex_string (this_frame->prev_pc.value));
+
+         frame_debug_printf ("this_frame=%d -> %s",
+                             this_frame->level,
+                             hex_string (this_frame->prev_pc.value));
        }
     }
 
@@ -1050,25 +1014,22 @@ get_frame_func_if_available (frame_info *this_frame, CORE_ADDR *pc)
       CORE_ADDR addr_in_block;
 
       /* Make certain that this, and not the adjacent, function is
-         found.  */
+        found.  */
       if (!get_frame_address_in_block_if_available (this_frame, &addr_in_block))
        {
          next_frame->prev_func.status = CC_UNAVAILABLE;
-         if (frame_debug)
-           fprintf_unfiltered (gdb_stdlog,
-                               "{ get_frame_func (this_frame=%d)"
-                               " -> unavailable }\n",
-                               this_frame->level);
+
+         frame_debug_printf ("this_frame=%d -> unavailable",
+                             this_frame->level);
        }
       else
        {
          next_frame->prev_func.status = CC_VALUE;
          next_frame->prev_func.addr = get_pc_function_start (addr_in_block);
-         if (frame_debug)
-           fprintf_unfiltered (gdb_stdlog,
-                               "{ get_frame_func (this_frame=%d) -> %s }\n",
-                               this_frame->level,
-                               hex_string (next_frame->prev_func.addr));
+
+         frame_debug_printf ("this_frame=%d -> %s",
+                             this_frame->level,
+                             hex_string (next_frame->prev_func.addr));
        }
     }
 
@@ -1256,66 +1217,61 @@ get_frame_register (struct frame_info *frame,
 struct value *
 frame_unwind_register_value (frame_info *next_frame, int regnum)
 {
-  struct gdbarch *gdbarch;
-  struct value *value;
+  FRAME_SCOPED_DEBUG_ENTER_EXIT;
 
   gdb_assert (next_frame != NULL);
-  gdbarch = frame_unwind_arch (next_frame);
-
-  if (frame_debug)
-    {
-      fprintf_unfiltered (gdb_stdlog,
-                         "{ frame_unwind_register_value "
-                         "(frame=%d,regnum=%d(%s),...) ",
-                         next_frame->level, regnum,
-                         user_reg_map_regnum_to_name (gdbarch, regnum));
-    }
+  gdbarch *gdbarch = frame_unwind_arch (next_frame);
+  frame_debug_printf ("frame=%d, regnum=%d(%s)",
+                     next_frame->level, regnum,
+                     user_reg_map_regnum_to_name (gdbarch, regnum));
 
   /* Find the unwinder.  */
   if (next_frame->unwind == NULL)
     frame_unwind_find_by_frame (next_frame, &next_frame->prologue_cache);
 
   /* Ask this frame to unwind its register.  */
-  value = next_frame->unwind->prev_register (next_frame,
-                                            &next_frame->prologue_cache,
-                                            regnum);
+  value *value = next_frame->unwind->prev_register (next_frame,
+                                                   &next_frame->prologue_cache,
+                                                   regnum);
 
   if (frame_debug)
     {
-      fprintf_unfiltered (gdb_stdlog, "->");
+      string_file debug_file;
+
+      fprintf_unfiltered (&debug_file, "  ->");
       if (value_optimized_out (value))
        {
-         fprintf_unfiltered (gdb_stdlog, " ");
-         val_print_not_saved (gdb_stdlog);
+         fprintf_unfiltered (&debug_file, " ");
+         val_print_not_saved (&debug_file);
        }
       else
        {
          if (VALUE_LVAL (value) == lval_register)
-           fprintf_unfiltered (gdb_stdlog, " register=%d",
+           fprintf_unfiltered (&debug_file, " register=%d",
                                VALUE_REGNUM (value));
          else if (VALUE_LVAL (value) == lval_memory)
-           fprintf_unfiltered (gdb_stdlog, " address=%s",
+           fprintf_unfiltered (&debug_file, " address=%s",
                                paddress (gdbarch,
                                          value_address (value)));
          else
-           fprintf_unfiltered (gdb_stdlog, " computed");
+           fprintf_unfiltered (&debug_file, " computed");
 
          if (value_lazy (value))
-           fprintf_unfiltered (gdb_stdlog, " lazy");
+           fprintf_unfiltered (&debug_file, " lazy");
          else
            {
              int i;
              const gdb_byte *buf = value_contents (value);
 
-             fprintf_unfiltered (gdb_stdlog, " bytes=");
-             fprintf_unfiltered (gdb_stdlog, "[");
+             fprintf_unfiltered (&debug_file, " bytes=");
+             fprintf_unfiltered (&debug_file, "[");
              for (i = 0; i < register_size (gdbarch, regnum); i++)
-               fprintf_unfiltered (gdb_stdlog, "%02x", buf[i]);
-             fprintf_unfiltered (gdb_stdlog, "]");
+               fprintf_unfiltered (&debug_file, "%02x", buf[i]);
+             fprintf_unfiltered (&debug_file, "]");
            }
        }
 
-      fprintf_unfiltered (gdb_stdlog, " }\n");
+      frame_debug_printf ("%s", debug_file.c_str ());
     }
 
   return value;
@@ -1471,7 +1427,8 @@ deprecated_frame_register_read (frame_info *frame, int regnum,
 
 bool
 get_frame_register_bytes (frame_info *frame, int regnum,
-                         CORE_ADDR offset, int len, gdb_byte *myaddr,
+                         CORE_ADDR offset,
+                         gdb::array_view<gdb_byte> buffer,
                          int *optimizedp, int *unavailablep)
 {
   struct gdbarch *gdbarch = get_frame_arch (frame);
@@ -1498,6 +1455,8 @@ get_frame_register_bytes (frame_info *frame, int regnum,
        break;  /* This register is not available on this architecture.  */
       maxsize += thissize;
     }
+
+  int len = buffer.size ();
   if (len > maxsize)
     error (_("Bad debug information detected: "
             "Attempt to read %d bytes from registers."), len);
@@ -1510,6 +1469,8 @@ get_frame_register_bytes (frame_info *frame, int regnum,
       if (curr_len > len)
        curr_len = len;
 
+      gdb_byte *myaddr = buffer.data ();
+
       if (curr_len == register_size (gdbarch, regnum))
        {
          enum lval_type lval;
@@ -1553,7 +1514,8 @@ get_frame_register_bytes (frame_info *frame, int regnum,
 
 void
 put_frame_register_bytes (struct frame_info *frame, int regnum,
-                         CORE_ADDR offset, int len, const gdb_byte *myaddr)
+                         CORE_ADDR offset,
+                         gdb::array_view<const gdb_byte> buffer)
 {
   struct gdbarch *gdbarch = get_frame_arch (frame);
 
@@ -1564,6 +1526,7 @@ put_frame_register_bytes (struct frame_info *frame, int regnum,
       regnum++;
     }
 
+  int len = buffer.size ();
   /* Copy the data.  */
   while (len > 0)
     {
@@ -1572,6 +1535,7 @@ put_frame_register_bytes (struct frame_info *frame, int regnum,
       if (curr_len > len)
        curr_len = len;
 
+      const gdb_byte *myaddr = buffer.data ();
       if (curr_len == register_size (gdbarch, regnum))
        {
          put_frame_register (frame, regnum, myaddr);
@@ -1617,12 +1581,9 @@ create_sentinel_frame (struct program_space *pspace, struct regcache *regcache)
   /* The sentinel frame has a special ID.  */
   frame->this_id.p = frame_id_status::COMPUTED;
   frame->this_id.value = sentinel_frame_id;
-  if (frame_debug)
-    {
-      fprintf_unfiltered (gdb_stdlog, "{ create_sentinel_frame (...) -> ");
-      fprint_frame (gdb_stdlog, frame);
-      fprintf_unfiltered (gdb_stdlog, " }\n");
-    }
+
+  frame_debug_printf ("  -> %s", frame->to_string ().c_str ());
+
   return frame;
 }
 
@@ -1685,10 +1646,129 @@ get_current_frame (void)
 }
 
 /* The "selected" stack frame is used by default for local and arg
-   access.  May be zero, for no selected frame.  */
-
+   access.
+
+   The "single source of truth" for the selected frame is the
+   SELECTED_FRAME_ID / SELECTED_FRAME_LEVEL pair.
+
+   Frame IDs can be saved/restored across reinitializing the frame
+   cache, while frame_info pointers can't (frame_info objects are
+   invalidated).  If we know the corresponding frame_info object, it
+   is cached in SELECTED_FRAME.
+
+   If SELECTED_FRAME_ID / SELECTED_FRAME_LEVEL are null_frame_id / -1,
+   and the target has stack and is stopped, the selected frame is the
+   current (innermost) frame.  This means that SELECTED_FRAME_LEVEL is
+   never 0 and SELECTED_FRAME_ID is never the ID of the innermost
+   frame.
+
+   If SELECTED_FRAME_ID / SELECTED_FRAME_LEVEL are null_frame_id / -1,
+   and the target has no stack or is executing, then there's no
+   selected frame.  */
+static frame_id selected_frame_id = null_frame_id;
+static int selected_frame_level = -1;
+
+/* The cached frame_info object pointing to the selected frame.
+   Looked up on demand by get_selected_frame.  */
 static struct frame_info *selected_frame;
 
+/* See frame.h.  */
+
+void
+save_selected_frame (frame_id *frame_id, int *frame_level)
+  noexcept
+{
+  *frame_id = selected_frame_id;
+  *frame_level = selected_frame_level;
+}
+
+/* See frame.h.  */
+
+void
+restore_selected_frame (frame_id frame_id, int frame_level)
+  noexcept
+{
+  /* save_selected_frame never returns level == 0, so we shouldn't see
+     it here either.  */
+  gdb_assert (frame_level != 0);
+
+  /* FRAME_ID can be null_frame_id only IFF frame_level is -1.  */
+  gdb_assert ((frame_level == -1 && !frame_id_p (frame_id))
+             || (frame_level != -1 && frame_id_p (frame_id)));
+
+  selected_frame_id = frame_id;
+  selected_frame_level = frame_level;
+
+  /* Will be looked up later by get_selected_frame.  */
+  selected_frame = nullptr;
+}
+
+/* See frame.h.  */
+
+void
+lookup_selected_frame (struct frame_id a_frame_id, int frame_level)
+{
+  struct frame_info *frame = NULL;
+  int count;
+
+  /* This either means there was no selected frame, or the selected
+     frame was the current frame.  In either case, select the current
+     frame.  */
+  if (frame_level == -1)
+    {
+      select_frame (get_current_frame ());
+      return;
+    }
+
+  /* select_frame never saves 0 in SELECTED_FRAME_LEVEL, so we
+     shouldn't see it here.  */
+  gdb_assert (frame_level > 0);
+
+  /* Restore by level first, check if the frame id is the same as
+     expected.  If that fails, try restoring by frame id.  If that
+     fails, nothing to do, just warn the user.  */
+
+  count = frame_level;
+  frame = find_relative_frame (get_current_frame (), &count);
+  if (count == 0
+      && frame != NULL
+      /* The frame ids must match - either both valid or both
+        outer_frame_id.  The latter case is not failsafe, but since
+        it's highly unlikely the search by level finds the wrong
+        frame, it's 99.9(9)% of the time (for all practical purposes)
+        safe.  */
+      && frame_id_eq (get_frame_id (frame), a_frame_id))
+    {
+      /* Cool, all is fine.  */
+      select_frame (frame);
+      return;
+    }
+
+  frame = frame_find_by_id (a_frame_id);
+  if (frame != NULL)
+    {
+      /* Cool, refound it.  */
+      select_frame (frame);
+      return;
+    }
+
+  /* Nothing else to do, the frame layout really changed.  Select the
+     innermost stack frame.  */
+  select_frame (get_current_frame ());
+
+  /* Warn the user.  */
+  if (frame_level > 0 && !current_uiout->is_mi_like_p ())
+    {
+      warning (_("Couldn't restore frame #%d in "
+                "current thread.  Bottom (innermost) frame selected:"),
+              frame_level);
+      /* For MI, we should probably have a notification about current
+        frame change.  But this error is not very likely, so don't
+        bother for now.  */
+      print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
+    }
+}
+
 bool
 has_stack_frames ()
 {
@@ -1716,9 +1796,7 @@ has_stack_frames ()
   return true;
 }
 
-/* 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.  */
+/* See frame.h.  */
 
 struct frame_info *
 get_selected_frame (const char *message)
@@ -1727,24 +1805,14 @@ get_selected_frame (const char *message)
     {
       if (message != NULL && !has_stack_frames ())
        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 ());
+
+      lookup_selected_frame (selected_frame_id, selected_frame_level);
     }
   /* There is always a frame.  */
   gdb_assert (selected_frame != NULL);
   return selected_frame;
 }
 
-/* If there is a selected frame, return it.  Otherwise, return NULL.  */
-
-struct frame_info *
-get_selected_frame_if_set (void)
-{
-  return 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().  */
@@ -1757,12 +1825,42 @@ deprecated_safe_get_selected_frame (void)
   return get_selected_frame (NULL);
 }
 
-/* Select frame FI (or NULL - to invalidate the current frame).  */
+/* Select frame FI (or NULL - to invalidate the selected frame).  */
 
 void
 select_frame (struct frame_info *fi)
 {
   selected_frame = fi;
+  selected_frame_level = frame_relative_level (fi);
+  if (selected_frame_level == 0)
+    {
+      /* Treat the current frame especially -- we want to always
+        save/restore it without warning, even if the frame ID changes
+        (see lookup_selected_frame).  E.g.:
+
+         // The current frame is selected, the target had just stopped.
+         {
+           scoped_restore_selected_frame restore_frame;
+           some_operation_that_changes_the_stack ();
+         }
+         // scoped_restore_selected_frame's dtor runs, but the
+         // original frame_id can't be found.  No matter whether it
+         // is found or not, we still end up with the now-current
+         // frame selected.  Warning in lookup_selected_frame in this
+         // case seems pointless.
+
+        Also get_frame_id may access the target's registers/memory,
+        and thus skipping get_frame_id optimizes the common case.
+
+        Saving the selected frame this way makes get_selected_frame
+        and restore_current_frame return/re-select whatever frame is
+        the innermost (current) then.  */
+      selected_frame_level = -1;
+      selected_frame_id = null_frame_id;
+    }
+  else
+    selected_frame_id = get_frame_id (fi);
+
   /* NOTE: cagney/2002-05-04: FI can be NULL.  This occurs when the
      frame is being invalidated.  */
 
@@ -1809,12 +1907,7 @@ create_new_frame (CORE_ADDR addr, CORE_ADDR pc)
 {
   struct frame_info *fi;
 
-  if (frame_debug)
-    {
-      fprintf_unfiltered (gdb_stdlog,
-                         "{ create_new_frame (addr=%s, pc=%s) ",
-                         hex_string (addr), hex_string (pc));
-    }
+  frame_debug_printf ("addr=%s, pc=%s", hex_string (addr), hex_string (pc));
 
   fi = FRAME_OBSTACK_ZALLOC (struct frame_info);
 
@@ -1839,12 +1932,7 @@ create_new_frame (CORE_ADDR addr, CORE_ADDR pc)
   fi->this_id.p = frame_id_status::COMPUTED;
   fi->this_id.value = frame_id_build (addr, pc);
 
-  if (frame_debug)
-    {
-      fprintf_unfiltered (gdb_stdlog, "-> ");
-      fprint_frame (gdb_stdlog, fi);
-      fprintf_unfiltered (gdb_stdlog, " }\n");
-    }
+  frame_debug_printf ("  -> %s", fi->to_string ().c_str ());
 
   return fi;
 }
@@ -1917,8 +2005,8 @@ reinit_frame_cache (void)
   sentinel_frame = NULL;               /* Invalidate cache */
   select_frame (NULL);
   frame_stash_invalidate ();
-  if (frame_debug)
-    fprintf_unfiltered (gdb_stdlog, "{ reinit_frame_cache () }\n");
+
+  frame_debug_printf ("generation=%d", frame_cache_generation);
 }
 
 /* Find where a register is saved (in memory or another register).
@@ -1986,12 +2074,8 @@ get_prev_frame_if_no_cycle (struct frame_info *this_frame)
        {
          /* Another frame with the same id was already in the stash.  We just
             detected a cycle.  */
-         if (frame_debug)
-           {
-             fprintf_unfiltered (gdb_stdlog, "-> ");
-             fprint_frame (gdb_stdlog, NULL);
-             fprintf_unfiltered (gdb_stdlog, " // this frame has same ID }\n");
-           }
+         frame_debug_printf ("  -> nullptr // this frame has same ID");
+
          this_frame->stop_reason = UNWIND_SAME_ID;
          /* Unlink.  */
          prev_frame->next = NULL;
@@ -2020,30 +2104,25 @@ get_prev_frame_if_no_cycle (struct frame_info *this_frame)
 static struct frame_info *
 get_prev_frame_always_1 (struct frame_info *this_frame)
 {
-  struct gdbarch *gdbarch;
+  FRAME_SCOPED_DEBUG_ENTER_EXIT;
 
   gdb_assert (this_frame != NULL);
-  gdbarch = get_frame_arch (this_frame);
 
   if (frame_debug)
     {
-      fprintf_unfiltered (gdb_stdlog, "{ get_prev_frame_always (this_frame=");
       if (this_frame != NULL)
-       fprintf_unfiltered (gdb_stdlog, "%d", this_frame->level);
+       frame_debug_printf ("this_frame=%d", this_frame->level);
       else
-       fprintf_unfiltered (gdb_stdlog, "<NULL>");
-      fprintf_unfiltered (gdb_stdlog, ") ");
+       frame_debug_printf ("this_frame=nullptr");
     }
 
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+
   /* 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");
-       }
+      frame_debug_printf ("  -> %s // cached",
+                         this_frame->prev->to_string ().c_str ());
       return this_frame->prev;
     }
 
@@ -2065,6 +2144,23 @@ get_prev_frame_always_1 (struct frame_info *this_frame)
   if (get_frame_type (this_frame) == INLINE_FRAME)
     return get_prev_frame_if_no_cycle (this_frame);
 
+  /* If this_frame is the current frame, then compute and stash its
+     frame id prior to fetching and computing the frame id of the
+     previous frame.  Otherwise, the cycle detection code in
+     get_prev_frame_if_no_cycle() will not work correctly.  When
+     get_frame_id() is called later on, an assertion error will be
+     triggered in the event of a cycle between the current frame and
+     its previous frame.
+
+     Note we do this after the INLINE_FRAME check above.  That is
+     because the inline frame's frame id computation needs to fetch
+     the frame id of its previous real stack frame.  I.e., we need to
+     avoid recursion in that case.  This is OK since we're sure the
+     inline frame won't create a cycle with the real stack frame.  See
+     inline_frame_this_id.  */
+  if (this_frame->level == 0)
+    get_frame_id (this_frame);
+
   /* Check that this frame is unwindable.  If it isn't, don't try to
      unwind to the prev frame.  */
   this_frame->stop_reason
@@ -2073,15 +2169,9 @@ get_prev_frame_always_1 (struct frame_info *this_frame)
 
   if (this_frame->stop_reason != UNWIND_NO_REASON)
     {
-      if (frame_debug)
-       {
-         enum unwind_stop_reason reason = this_frame->stop_reason;
-
-         fprintf_unfiltered (gdb_stdlog, "-> ");
-         fprint_frame (gdb_stdlog, NULL);
-         fprintf_unfiltered (gdb_stdlog, " // %s }\n",
-                             frame_stop_reason_symbol_string (reason));
-       }
+      frame_debug_printf
+       ("  -> nullptr // %s",
+        frame_stop_reason_symbol_string (this_frame->stop_reason));
       return NULL;
     }
 
@@ -2098,7 +2188,7 @@ get_prev_frame_always_1 (struct frame_info *this_frame)
       CORE_ADDR this_pc_in_block;
       struct minimal_symbol *morestack_msym;
       const char *morestack_name = NULL;
-      
+
       /* gcc -fsplit-stack __morestack can continue the stack anywhere.  */
       this_pc_in_block = get_frame_address_in_block (this_frame);
       morestack_msym = lookup_minimal_symbol_by_pc (this_pc_in_block).minsym;
@@ -2106,13 +2196,7 @@ get_prev_frame_always_1 (struct frame_info *this_frame)
        morestack_name = morestack_msym->linkage_name ();
       if (!morestack_name || strcmp (morestack_name, "__morestack") != 0)
        {
-         if (frame_debug)
-           {
-             fprintf_unfiltered (gdb_stdlog, "-> ");
-             fprint_frame (gdb_stdlog, NULL);
-             fprintf_unfiltered (gdb_stdlog,
-                                 " // this frame ID is inner }\n");
-           }
+         frame_debug_printf ("  -> nullptr // this frame ID is inner");
          this_frame->stop_reason = UNWIND_INNER_ID;
          return NULL;
        }
@@ -2152,13 +2236,7 @@ get_prev_frame_always_1 (struct frame_info *this_frame)
       if ((lval == lval_memory && lval == nlval && addr == naddr)
          || (lval == lval_register && lval == nlval && realnum == nrealnum))
        {
-         if (frame_debug)
-           {
-             fprintf_unfiltered (gdb_stdlog, "-> ");
-             fprint_frame (gdb_stdlog, NULL);
-             fprintf_unfiltered (gdb_stdlog, " // no saved PC }\n");
-           }
-
+         frame_debug_printf ("  -> nullptr // no saved PC");
          this_frame->stop_reason = UNWIND_NO_SAVED_PC;
          this_frame->prev = NULL;
          return NULL;
@@ -2194,9 +2272,9 @@ get_prev_frame_always (struct frame_info *this_frame)
              size_t size;
 
              /* The error needs to live as long as the frame does.
-                Allocate using stack local STOP_STRING then assign the
-                pointer to the frame, this allows the STOP_STRING on the
-                frame to be of type 'const char *'.  */
+                Allocate using stack local STOP_STRING then assign the
+                pointer to the frame, this allows the STOP_STRING on the
+                frame to be of type 'const char *'.  */
              size = ex.message->size () + 1;
              stop_string = (char *) frame_obstack_zalloc (size);
              memcpy (stop_string, ex.what (), size);
@@ -2260,12 +2338,7 @@ get_prev_frame_raw (struct frame_info *this_frame)
   this_frame->prev = prev_frame;
   prev_frame->next = this_frame;
 
-  if (frame_debug)
-    {
-      fprintf_unfiltered (gdb_stdlog, "-> ");
-      fprint_frame (gdb_stdlog, prev_frame);
-      fprintf_unfiltered (gdb_stdlog, " }\n");
-    }
+  frame_debug_printf ("  -> %s", prev_frame->to_string ().c_str ());
 
   return prev_frame;
 }
@@ -2278,12 +2351,10 @@ frame_debug_got_null_frame (struct frame_info *this_frame,
 {
   if (frame_debug)
     {
-      fprintf_unfiltered (gdb_stdlog, "{ get_prev_frame (this_frame=");
       if (this_frame != NULL)
-       fprintf_unfiltered (gdb_stdlog, "%d", this_frame->level);
+       frame_debug_printf ("this_frame=%d -> %s", this_frame->level, reason);
       else
-       fprintf_unfiltered (gdb_stdlog, "<NULL>");
-      fprintf_unfiltered (gdb_stdlog, ") -> // %s}\n", reason);
+       frame_debug_printf ("this_frame=nullptr -> %s", reason);
     }
 }
 
@@ -2318,9 +2389,8 @@ inside_main_func (frame_info *this_frame)
 
   /* Convert any function descriptor addresses into the actual function
      code address.  */
-  sym_addr
-    = gdbarch_convert_from_func_ptr_addr (get_frame_arch (this_frame),
-                                         sym_addr, current_top_target ());
+  sym_addr = gdbarch_convert_from_func_ptr_addr
+    (get_frame_arch (this_frame), sym_addr, current_inferior ()->top_target ());
 
   return sym_addr == get_frame_func (this_frame);
 }
@@ -2350,6 +2420,8 @@ inside_entry_func (frame_info *this_frame)
 struct frame_info *
 get_prev_frame (struct frame_info *this_frame)
 {
+  FRAME_SCOPED_DEBUG_ENTER_EXIT;
+
   CORE_ADDR frame_pc;
   int frame_pc_p;
 
@@ -2357,16 +2429,6 @@ get_prev_frame (struct frame_info *this_frame)
      something should be calling get_selected_frame() or
      get_current_frame().  */
   gdb_assert (this_frame != NULL);
-  
-  /* If this_frame is the current frame, then compute and stash
-     its frame id prior to fetching and computing the frame id of the
-     previous frame.  Otherwise, the cycle detection code in
-     get_prev_frame_if_no_cycle() will not work correctly.  When
-     get_frame_id() is called later on, an assertion error will
-     be triggered in the event of a cycle between the current
-     frame and its previous frame.  */
-  if (this_frame->level == 0)
-    get_frame_id (this_frame);
 
   frame_pc_p = get_frame_pc_if_available (this_frame, &frame_pc);
 
@@ -2376,9 +2438,9 @@ get_prev_frame (struct frame_info *this_frame)
      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 
+     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
       && get_frame_type (this_frame) == NORMAL_FRAME
@@ -2423,7 +2485,7 @@ get_prev_frame (struct frame_info *this_frame)
      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 
+     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.  */
@@ -2458,7 +2520,7 @@ get_prev_frame_id_by_id (struct frame_id id)
 {
   struct frame_id prev_id;
   struct frame_info *frame;
-  
+
   frame = frame_find_by_id (id);
 
   if (frame != NULL)
@@ -2749,9 +2811,9 @@ get_frame_address_space (struct frame_info *frame)
 
 void
 get_frame_memory (struct frame_info *this_frame, CORE_ADDR addr,
-                 gdb_byte *buf, int len)
+                 gdb::array_view<gdb_byte> buffer)
 {
-  read_memory (addr, buf, len);
+  read_memory (addr, buffer.data (), buffer.size ());
 }
 
 LONGEST
@@ -2776,10 +2838,10 @@ get_frame_memory_unsigned (struct frame_info *this_frame, CORE_ADDR addr,
 
 bool
 safe_frame_unwind_memory (struct frame_info *this_frame,
-                         CORE_ADDR addr, gdb_byte *buf, int len)
+                         CORE_ADDR addr, gdb::array_view<gdb_byte> buffer)
 {
   /* NOTE: target_read_memory returns zero on success!  */
-  return target_read_memory (addr, buf, len) == 0;
+  return target_read_memory (addr, buffer.data (), buffer.size ()) == 0;
 }
 
 /* Architecture methods.  */
@@ -2808,11 +2870,9 @@ frame_unwind_arch (struct frame_info *next_frame)
 
       next_frame->prev_arch.arch = arch;
       next_frame->prev_arch.p = true;
-      if (frame_debug)
-       fprintf_unfiltered (gdb_stdlog,
-                           "{ frame_unwind_arch (next_frame=%d) -> %s }\n",
-                           next_frame->level,
-                           gdbarch_bfd_arch_info (arch)->printable_name);
+      frame_debug_printf ("next_frame=%d -> %s",
+                         next_frame->level,
+                         gdbarch_bfd_arch_info (arch)->printable_name);
     }
 
   return next_frame->prev_arch.arch;
@@ -3030,17 +3090,18 @@ _initialize_frame ()
 
   frame_stash_create ();
 
-  gdb::observers::target_changed.attach (frame_observer_target_changed);
+  gdb::observers::target_changed.attach (frame_observer_target_changed,
+                                        "frame");
 
   add_basic_prefix_cmd ("backtrace", class_maintenance, _("\
 Set backtrace specific variables.\n\
 Configure backtrace variables such as the backtrace limit"),
-                       &set_backtrace_cmdlist, "set backtrace ",
+                       &set_backtrace_cmdlist,
                        0/*allow-unknown*/, &setlist);
   add_show_prefix_cmd ("backtrace", class_maintenance, _("\
 Show backtrace specific variables.\n\
 Show backtrace variables such as the backtrace limit."),
-                      &show_backtrace_cmdlist, "show backtrace ",
+                      &show_backtrace_cmdlist,
                       0/*allow-unknown*/, &showlist);
 
   add_setshow_uinteger_cmd ("limit", class_obscure,
@@ -3059,11 +3120,11 @@ Literal \"unlimited\" or zero means no limit."),
      set_backtrace_option_defs, &set_backtrace_cmdlist, &show_backtrace_cmdlist);
 
   /* Debug this files internals.  */
-  add_setshow_zuinteger_cmd ("frame", class_maintenance, &frame_debug,  _("\
+  add_setshow_boolean_cmd ("frame", class_maintenance, &frame_debug,  _("\
 Set frame debugging."), _("\
 Show frame debugging."), _("\
 When non-zero, frame specific internal debugging is enabled."),
-                            NULL,
-                            show_frame_debug,
-                            &setdebuglist, &showdebuglist);
+                          NULL,
+                          show_frame_debug,
+                          &setdebuglist, &showdebuglist);
 }
This page took 0.038027 seconds and 4 git commands to generate.