diff --git a/gdb/frame-unwind.c b/gdb/frame-unwind.c
index fecd1070e912..ad8ebb29d736 100644
--- a/gdb/frame-unwind.c
+++ b/gdb/frame-unwind.c
@@ -313,14 +313,26 @@ frame_unwind_got_constant (const frame_info_ptr &frame, int regnum,
 }
 
 struct value *
-frame_unwind_got_bytes (const frame_info_ptr &frame, int regnum, const gdb_byte *buf)
+frame_unwind_got_bytes (const frame_info_ptr &frame, int regnum,
+			gdb::array_view<const gdb_byte> buf)
 {
   struct gdbarch *gdbarch = frame_unwind_arch (frame);
   struct value *reg_val;
 
   reg_val = value::zero (register_type (gdbarch, regnum), not_lval);
-  memcpy (reg_val->contents_raw ().data (), buf,
-	  register_size (gdbarch, regnum));
+  gdb::array_view<gdb_byte> val_contents = reg_val->contents_raw ();
+
+  /* The value's contents buffer is zeroed on allocation so if buf is
+     smaller, the remaining space will be filled with zero.
+
+     This can happen when unwinding through signal frames.  For example, if
+     an AArch64 program doesn't use SVE, then the Linux kernel will only
+     save in the signal frame the first 128 bits of the vector registers,
+     which is their minimum size, even if the vector length says they're
+     bigger.  */
+  gdb_assert (buf.size () <= val_contents.size ());
+
+  memcpy (val_contents.data (), buf.data (), buf.size ());
   return reg_val;
 }
 
diff --git a/gdb/frame-unwind.h b/gdb/frame-unwind.h
index 53fcd6869e95..36e7fbdb4f9c 100644
--- a/gdb/frame-unwind.h
+++ b/gdb/frame-unwind.h
@@ -226,7 +226,7 @@ value *frame_unwind_got_constant (const frame_info_ptr &frame, int regnum,
    inside BUF.  */
 
 value *frame_unwind_got_bytes (const frame_info_ptr &frame, int regnum,
-			       const gdb_byte *buf);
+			       gdb::array_view<const gdb_byte> buf);
 
 /* Return a value which indicates that FRAME's saved version of REGNUM
    has a known constant (computed) value of ADDR.  Convert the
diff --git a/gdb/jit.c b/gdb/jit.c
index ed3b26cd4bd1..e068b0a4b572 100644
--- a/gdb/jit.c
+++ b/gdb/jit.c
@@ -1094,7 +1094,7 @@ jit_frame_prev_register (const frame_info_ptr &this_frame, void **cache, int reg
     return frame_unwind_got_optimized (this_frame, reg);
 
   gdbarch = priv->regcache->arch ();
-  gdb_byte *buf = (gdb_byte *) alloca (register_size (gdbarch, reg));
+  gdb::byte_vector buf (register_size (gdbarch, reg));
   enum register_status status = priv->regcache->cooked_read (reg, buf);
 
   if (status == REG_VALID)
diff --git a/gdb/python/py-unwind.c b/gdb/python/py-unwind.c
index 68deaf98d81f..c1a01bf7cfe4 100644
--- a/gdb/python/py-unwind.c
+++ b/gdb/python/py-unwind.c
@@ -812,7 +812,7 @@ pyuw_prev_register (const frame_info_ptr &this_frame, void **cache_ptr,
   for (; reg_info < reg_info_end; ++reg_info)
     {
       if (regnum == reg_info->num)
-	return frame_unwind_got_bytes (this_frame, regnum, reg_info->data.get ());
+	return frame_unwind_got_bytes (this_frame, regnum, reg_info->data);
     }
 
   return frame_unwind_got_optimized (this_frame, regnum);
@@ -936,8 +936,9 @@ pyuw_sniffer (const struct frame_unwind *self, const frame_info_ptr &this_frame,
 
 	cached_reg_t *cached = new (&cached_frame->reg[i]) cached_reg_t ();
 	cached->num = reg->number;
-	cached->data.reset ((gdb_byte *) xmalloc (data_size));
-	memcpy (cached->data.get (), value->contents ().data (), data_size);
+	cached->data.resize (data_size);
+	gdb::array_view<const gdb_byte> contents = value->contents ();
+	cached->data.assign (contents.begin (), contents.end ());
       }
   }
 
diff --git a/gdb/regcache.h b/gdb/regcache.h
index 65e9f7bb79da..739172a249b8 100644
--- a/gdb/regcache.h
+++ b/gdb/regcache.h
@@ -177,7 +177,7 @@ using register_read_ftype
 struct cached_reg_t
 {
   int num;
-  gdb::unique_xmalloc_ptr<gdb_byte> data;
+  gdb::byte_vector data;
 
   cached_reg_t () = default;
   cached_reg_t (cached_reg_t &&rhs) = default;
diff --git a/gdb/remote.c b/gdb/remote.c
index 6ffc51e4e2f5..2da2c5a4789a 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -8225,13 +8225,12 @@ Packet: '%s'\n"),
 			   hex_string (pnum), p, buf);
 
 		  cached_reg.num = reg->regnum;
-		  cached_reg.data.reset ((gdb_byte *)
-					 xmalloc (register_size (event->arch,
-								 reg->regnum)));
+		  cached_reg.data.resize (register_size (event->arch,
+							 reg->regnum));
 
 		  p = p1 + 1;
-		  fieldsize = hex2bin (p, cached_reg.data.get (),
-				       register_size (event->arch, reg->regnum));
+		  fieldsize = hex2bin (p, cached_reg.data.data (),
+				       cached_reg.data.size ());
 		  p += 2 * fieldsize;
 		  if (fieldsize < register_size (event->arch, reg->regnum))
 		    warning (_("Remote reply is too short: %s"), buf);
@@ -8572,7 +8571,7 @@ remote_target::process_stop_reply (stop_reply_up stop_reply,
 
 	  for (cached_reg_t &reg : stop_reply->regcache)
 	    {
-	      regcache->raw_supply (reg.num, reg.data.get ());
+	      regcache->raw_supply (reg.num, reg.data);
 	      rs->last_seen_expedited_registers.insert (reg.num);
 	    }
 	}
diff --git a/gdb/trad-frame.h b/gdb/trad-frame.h
index ca8792baa17d..ef84a24c0bc7 100644
--- a/gdb/trad-frame.h
+++ b/gdb/trad-frame.h
@@ -122,6 +122,7 @@ struct trad_frame_saved_reg
 
     m_kind = trad_frame_saved_reg_kind::VALUE_BYTES;
     m_reg.value_bytes = data;
+    m_reg.bytes_len = bytes.size ();
   }
 
   /* Getters */
@@ -144,10 +145,10 @@ struct trad_frame_saved_reg
     return m_reg.addr;
   }
 
-  const gdb_byte *value_bytes () const
+  gdb::array_view<const gdb_byte> value_bytes () const
   {
     gdb_assert (m_kind == trad_frame_saved_reg_kind::VALUE_BYTES);
-    return m_reg.value_bytes;
+    return { m_reg.value_bytes, m_reg.bytes_len };
   }
 
   /* Convenience functions, return true if the register has been
@@ -185,7 +186,10 @@ struct trad_frame_saved_reg
     LONGEST value;
     int realreg;
     LONGEST addr;
-    const gdb_byte *value_bytes;
+    struct {
+      const gdb_byte *value_bytes;
+      size_t bytes_len;
+    };
   } m_reg;
 };
 
