sim: move -Werror disabling to Makefile
[binutils-gdb.git] / gdb / frame.c
index cc44a04787a4038f9989a61a25886968bb674625..d2e14c831a09a3e03333ed7b75ad8bdcc3f4cd2f 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.
 
@@ -317,17 +317,15 @@ 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.  */
@@ -375,43 +373,44 @@ 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));
-
-  fprintf_unfiltered (file, ",");
+    res += std::string ("stack=") + hex_string (id.stack_addr);
 
-  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
@@ -494,7 +493,7 @@ fprint_frame (struct ui_file *file, struct frame_info *fi)
   else if (fi->this_id.p == frame_id_status::COMPUTING)
     fprintf_unfiltered (file, "<computing>");
   else
-    fprint_frame_id (file, fi->this_id.value);
+    fprintf_unfiltered (file, "%s", fi->this_id.value.to_string ().c_str ());
   fprintf_unfiltered (file, ",");
 
   fprintf_unfiltered (file, "func=");
@@ -594,16 +593,13 @@ compute_frame_id (struct frame_info *fi)
       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");
-       }
+       fprintf_unfiltered (gdb_stdlog, "-> %s }\n",
+                           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 +675,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;
 
@@ -750,11 +746,8 @@ frame_id_p (frame_id l)
   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);
-    }
+    fprintf_unfiltered (gdb_stdlog, "{ frame_id_p (l=%s) -> %d }\n",
+                       l.to_string ().c_str (), p);
 
   return p;
 }
@@ -798,13 +791,8 @@ frame_id_eq (frame_id l, frame_id r)
     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);
-    }
+    fprintf_unfiltered (gdb_stdlog, "{ frame_id_eq (l=%s,r=%s) -> %d }\n",
+                       l.to_string ().c_str (), r.to_string ().c_str (), eq);
 
   return eq;
 }
@@ -881,13 +869,9 @@ frame_id_inner (struct gdbarch *gdbarch, struct frame_id l, struct frame_id r)
     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);
-    }
+    fprintf_unfiltered (gdb_stdlog, "{ frame_id_inner (l=%s,r=%s) -> %d }\n",
+                       l.to_string ().c_str (), r.to_string ().c_str (),
+                       inner);
 
   return inner;
 }
@@ -1050,7 +1034,7 @@ 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;
@@ -1471,7 +1455,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 +1483,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 +1497,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 +1542,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 +1554,7 @@ put_frame_register_bytes (struct frame_info *frame, int regnum,
       regnum++;
     }
 
+  int len = buffer.size ();
   /* Copy the data.  */
   while (len > 0)
     {
@@ -1572,6 +1563,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);
@@ -1653,7 +1645,7 @@ get_current_frame (void)
      have registers is very confusing.  Besides, "printcmd.exp"
      explicitly checks that ``print $pc'' with no registers prints "No
      registers".  */
-  if (!target_has_registers)
+  if (!target_has_registers ())
     error (_("No registers."));
   if (!target_has_stack ())
     error (_("No stack."));
@@ -1685,14 +1677,134 @@ 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 ()
 {
-  if (!target_has_registers || !target_has_stack () || !target_has_memory ())
+  if (!target_has_registers () || !target_has_stack ()
+      || !target_has_memory ())
     return false;
 
   /* Traceframes are effectively a substitute for the live inferior.  */
@@ -1715,9 +1827,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)
@@ -1726,24 +1836,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().  */
@@ -1756,12 +1856,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.  */
 
@@ -2064,6 +2194,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
@@ -2097,7 +2244,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;
@@ -2193,9 +2340,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);
@@ -2291,22 +2438,36 @@ frame_debug_got_null_frame (struct frame_info *this_frame,
 static bool
 inside_main_func (frame_info *this_frame)
 {
-  if (symfile_objfile == nullptr)
+  if (current_program_space->symfile_object_file == nullptr)
     return false;
 
+  CORE_ADDR sym_addr;
+  const char *name = main_name ();
   bound_minimal_symbol msymbol
-    = lookup_minimal_symbol (main_name (), NULL, symfile_objfile);
+    = lookup_minimal_symbol (name, NULL,
+                            current_program_space->symfile_object_file);
   if (msymbol.minsym == nullptr)
-    return false;
+    {
+      /* In some language (for example Fortran) there will be no minimal
+        symbol with the name of the main function.  In this case we should
+        search the full symbols to see if we can find a match.  */
+      struct block_symbol bs = lookup_symbol (name, NULL, VAR_DOMAIN, 0);
+      if (bs.symbol == nullptr)
+       return false;
+
+      const struct block *block = SYMBOL_BLOCK_VALUE (bs.symbol);
+      gdb_assert (block != nullptr);
+      sym_addr = BLOCK_START (block);
+    }
+  else
+    sym_addr = BMSYMBOL_VALUE_ADDRESS (msymbol);
 
-  /* Make certain that the code, and not descriptor, address is
-     returned.  */
-  CORE_ADDR maddr
-    = gdbarch_convert_from_func_ptr_addr (get_frame_arch (this_frame),
-                                         BMSYMBOL_VALUE_ADDRESS (msymbol),
-                                         current_top_target ());
+  /* 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_inferior ()->top_target ());
 
-  return maddr == get_frame_func (this_frame);
+  return sym_addr == get_frame_func (this_frame);
 }
 
 /* Test whether THIS_FRAME is inside the process entry point function.  */
@@ -2341,16 +2502,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);
 
@@ -2360,9 +2511,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
@@ -2407,7 +2558,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.  */
@@ -2442,7 +2593,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)
@@ -2733,9 +2884,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
@@ -2760,10 +2911,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.  */
@@ -2980,8 +3131,6 @@ static struct cmd_list_element *show_backtrace_cmdlist;
 
 using boolean_option_def
   = gdb::option::boolean_option_def<set_backtrace_options>;
-using uinteger_option_def
-  = gdb::option::uinteger_option_def<set_backtrace_options>;
 
 const gdb::option::option_def set_backtrace_option_defs[] = {
 
@@ -3016,17 +3165,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,