[binutils-gdb] gdb/dwarf2: pass around DWARF expressions as gdb::array_view

Simon Marchi via Gdb-cvs <[email protected]>
Newsgroups gmane.comp.gdb.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=5a3726062a2c50b28592551cadf20118fe603b29

commit 5a3726062a2c50b28592551cadf20118fe603b29
Author: Simon Marchi <[email protected]>
Date:   Tue Apr 28 20:55:42 2026 -0400

    gdb/dwarf2: pass around DWARF expressions as gdb::array_view
    
    This patch converts a bunch of functions to take or return DWARF
    expressions as `gdb::array_view<const gdb_byte>`, instead of raw pointer
    and size.  It doesn't do any non-trivial change to function
    implementations, but the idea is that we could change them (for example
    dwarf_expr_context::execute_stack_op) to operate on the array view
    directly, giving us bounds checking when building in debug mode.  But
    that is not as trivial.
    
    This patch also doesn't change structure fields to array_views (for
    instance, dwarf2_loclist_baton), because that would make them
    non-trivially constructible, and we'd (technically) need to change how
    they are allocated.
    
    Change-Id: I45a40e4d00edfb54b7fdff1447806da5bbe06183
    Approved-By: Tom Tromey <[email protected]>

Diff:
---
 gdb/compile/compile-loc2c.c |  83 ++++---
 gdb/compile/compile.h       |  10 +-
 gdb/dwarf2/attribute.h      |   4 +
 gdb/dwarf2/call-site.h      |   9 +
 gdb/dwarf2/expr.c           |  84 +++----
 gdb/dwarf2/expr.h           |  36 ++-
 gdb/dwarf2/frame.c          |  40 ++--
 gdb/dwarf2/frame.h          |  20 +-
 gdb/dwarf2/loc.c            | 543 ++++++++++++++++++++------------------------
 gdb/dwarf2/loc.h            |  64 ++++--
 gdb/dwarf2/read.c           |  89 +++-----
 gdb/symtab.h                |  11 +-
 12 files changed, 473 insertions(+), 520 deletions(-)

diff --git a/gdb/compile/compile-loc2c.c b/gdb/compile/compile-loc2c.c
index dae3e2ebd6b..9f189ef1cc7 100644
--- a/gdb/compile/compile-loc2c.c
+++ b/gdb/compile/compile-loc2c.c
@@ -70,16 +70,18 @@ struct insn_info
    TO_DO is a list of bytecodes which must be examined; it may be
    added to by this function.
    BYTE_ORDER and ADDR_SIZE describe this bytecode in the obvious way.
-   OP_PTR and OP_END are the bounds of the DWARF expression.  */
+   EXPR is the DWARF expression.  */
 
 static void
 compute_stack_depth_worker (int start, int *need_tempvar,
 			    std::vector<struct insn_info> *info,
 			    std::vector<int> *to_do,
 			    enum bfd_endian byte_order, unsigned int addr_size,
-			    const gdb_byte *op_ptr, const gdb_byte *op_end)
+			    gdb::array_view<const gdb_byte> expr)
 {
-  const gdb_byte * const base = op_ptr;
+  const gdb_byte *const base = expr.data ();
+  const gdb_byte *op_ptr = expr.data ();
+  const gdb_byte *const op_end = expr.data () + expr.size ();
   int stack_depth;
 
   op_ptr += start;
@@ -378,7 +380,7 @@ compute_stack_depth_worker (int start, int *need_tempvar,
    generator).
    IS_TLS is an out parameter which is set if this expression refers
    to a TLS variable.
-   OP_PTR and OP_END are the bounds of the DWARF expression.
+   EXPR is the DWARF expression.
    INITIAL_DEPTH is the initial depth of the DWARF expression stack.
    INFO is an array of insn_info objects, indexed by offset from the
    start of the DWARF expression.
@@ -388,14 +390,14 @@ compute_stack_depth_worker (int start, int *need_tempvar,
 static int
 compute_stack_depth (enum bfd_endian byte_order, unsigned int addr_size,
 		     int *need_tempvar, int *is_tls,
-		     const gdb_byte *op_ptr, const gdb_byte *op_end,
+		     gdb::array_view<const gdb_byte> expr,
 		     int initial_depth,
 		     std::vector<struct insn_info> *info)
 {
   std::vector<int> to_do;
-  int stack_depth, i;
+  int stack_depth;
 
-  info->resize (op_end - op_ptr);
+  info->resize (expr.size ());
 
   to_do.push_back (0);
   (*info)[0].depth = initial_depth;
@@ -406,14 +408,13 @@ compute_stack_depth (enum bfd_endian byte_order, unsigned int addr_size,
       int ndx = to_do.back ();
       to_do.pop_back ();
 
-      compute_stack_depth_worker (ndx, need_tempvar, info, &to_do,
-				  byte_order, addr_size,
-				  op_ptr, op_end);
+      compute_stack_depth_worker (ndx, need_tempvar, info, &to_do, byte_order,
+				  addr_size, expr);
     }
 
   stack_depth = 0;
   *is_tls = 0;
-  for (i = 0; i < op_end - op_ptr; ++i)
+  for (int i = 0; i < expr.size (); ++i)
     {
       if ((*info)[i].depth > stack_depth)
 	stack_depth = (*info)[i].depth;
@@ -579,7 +580,7 @@ pushf_register (int indent, string_file *stream,
 
    ADDR_SIZE is the DWARF address size to use.
 
-   OPT_PTR and OP_END are the bounds of the DWARF expression.
+   EXPR is the DWARF expression.
 
    If non-NULL, INITIAL points to an initial value to write to the
    stack.  If NULL, no initial value is written.
@@ -595,7 +596,7 @@ do_compile_dwarf_expr_to_c (int indent, string_file *stream,
 			    struct gdbarch *arch,
 			    std::vector<bool> &registers_used,
 			    unsigned int addr_size,
-			    const gdb_byte *op_ptr, const gdb_byte *op_end,
+			    gdb::array_view<const gdb_byte> expr,
 			    CORE_ADDR *initial,
 			    dwarf2_per_cu *per_cu,
 			    dwarf2_per_objfile *per_objfile)
@@ -605,7 +606,6 @@ do_compile_dwarf_expr_to_c (int indent, string_file *stream,
   static unsigned int scope;
 
   enum bfd_endian byte_order = gdbarch_byte_order (arch);
-  const gdb_byte * const base = op_ptr;
   int need_tempvar = 0;
   int is_tls = 0;
   std::vector<struct insn_info> info;
@@ -620,7 +620,7 @@ do_compile_dwarf_expr_to_c (int indent, string_file *stream,
 
   stack_depth = compute_stack_depth (byte_order, addr_size,
 				     &need_tempvar, &is_tls,
-				     op_ptr, op_end, initial != NULL,
+				     expr, initial != NULL,
 				     &info);
 
   /* This is a hack until we can add a feature to glibc to let us
@@ -668,6 +668,10 @@ do_compile_dwarf_expr_to_c (int indent, string_file *stream,
   if (initial != NULL)
     pushf (indent, stream, "%s", core_addr_to_string (*initial));
 
+  const gdb_byte *const base = expr.data ();
+  const gdb_byte *op_ptr = base;
+  const gdb_byte *const op_end = expr.data () + expr.size ();
+
   while (op_ptr < op_end)
     {
       enum dwarf_location_atom op = (enum dwarf_location_atom) *op_ptr;
@@ -880,8 +884,6 @@ do_compile_dwarf_expr_to_c (int indent, string_file *stream,
 	  break;
 	case DW_OP_fbreg:
 	  {
-	    const gdb_byte *datastart;
-	    size_t datalen;
 	    const struct block *b;
 	    struct symbol *framefunc;
 	    char fb_name[50];
@@ -896,8 +898,8 @@ do_compile_dwarf_expr_to_c (int indent, string_file *stream,
 	    if (!framefunc)
 	      error (_("No function found for block"));
 
-	    func_get_frame_base_dwarf_block (framefunc, pc,
-					     &datastart, &datalen);
+	    auto frame_base_expr
+	      = func_get_frame_base_dwarf_block (framefunc, pc);
 
 	    op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
 
@@ -906,12 +908,10 @@ do_compile_dwarf_expr_to_c (int indent, string_file *stream,
 	    xsnprintf (fb_name, sizeof (fb_name), "__frame_base_%ld",
 		       (long) (op_ptr - base));
 
-	    do_compile_dwarf_expr_to_c (indent, stream,
-					GCC_UINTPTR, fb_name,
-					sym, pc,
-					arch, registers_used, addr_size,
-					datastart, datastart + datalen,
-					NULL, per_cu, per_objfile);
+	    do_compile_dwarf_expr_to_c (indent, stream, GCC_UINTPTR, fb_name,
+					sym, pc, arch, registers_used,
+					addr_size, frame_base_expr, nullptr,
+					per_cu, per_objfile);
 
 	    pushf (indent, stream, "%s + %s", fb_name, hex_string (offset));
 	  }
@@ -1074,11 +1074,10 @@ do_compile_dwarf_expr_to_c (int indent, string_file *stream,
 	    int regnum;
 	    CORE_ADDR text_offset;
 	    LONGEST off;
-	    const gdb_byte *cfa_start, *cfa_end;
+	    gdb::array_view<const gdb_byte> cfa_expr;
 
-	    if (dwarf2_fetch_cfa_info (arch, pc, per_cu,
-				       &regnum, &off,
-				       &text_offset, &cfa_start, &cfa_end))
+	    if (dwarf2_fetch_cfa_info (arch, pc, per_cu, &regnum, &off,
+				       &text_offset, cfa_expr))
 	      {
 		/* Register.  */
 		pushf_register (indent, stream, registers_used, arch, regnum,
@@ -1094,12 +1093,11 @@ do_compile_dwarf_expr_to_c (int indent, string_file *stream,
 		xsnprintf (cfa_name, sizeof (cfa_name),
 			   "__cfa_%ld", (long) (op_ptr - base));
 
-		do_compile_dwarf_expr_to_c (indent, stream,
-					    GCC_UINTPTR, cfa_name,
-					    sym, pc, arch, registers_used,
-					    addr_size,
-					    cfa_start, cfa_end,
-					    &text_offset, per_cu, per_objfile);
+		do_compile_dwarf_expr_to_c (indent, stream, GCC_UINTPTR,
+					    cfa_name, sym, pc, arch,
+					    registers_used, addr_size,
+					    cfa_expr, &text_offset, per_cu,
+					    per_objfile);
 		pushf (indent, stream, "%s", cfa_name);
 	      }
 	  }
@@ -1146,13 +1144,13 @@ compile_dwarf_expr_to_c (string_file *stream, const char *result_name,
 			 struct gdbarch *arch,
 			 std::vector<bool> &registers_used,
 			 unsigned int addr_size,
-			 const gdb_byte *op_ptr, const gdb_byte *op_end,
+			 gdb::array_view<const gdb_byte> expr,
 			 dwarf2_per_cu *per_cu,
 			 dwarf2_per_objfile *per_objfile)
 {
   do_compile_dwarf_expr_to_c (2, stream, GCC_UINTPTR, result_name, sym, pc,
-			      arch, registers_used, addr_size, op_ptr, op_end,
-			      NULL, per_cu, per_objfile);
+			      arch, registers_used, addr_size, expr, nullptr,
+			      per_cu, per_objfile);
 }
 
 /* See compile.h.  */
@@ -1165,12 +1163,11 @@ compile_dwarf_bounds_to_c (string_file *stream,
 			   struct gdbarch *arch,
 			   std::vector<bool> &registers_used,
 			   unsigned int addr_size,
-			   const gdb_byte *op_ptr, const gdb_byte *op_end,
+			   gdb::array_view<const gdb_byte> expr,
 			   dwarf2_per_cu *per_cu,
 			   dwarf2_per_objfile *per_objfile)
 {
-  do_compile_dwarf_expr_to_c (2, stream, "unsigned long ", result_name,
-			      sym, pc, arch, registers_used,
-			      addr_size, op_ptr, op_end, NULL, per_cu,
-			      per_objfile);
+  do_compile_dwarf_expr_to_c (2, stream, "unsigned long ", result_name, sym,
+			      pc, arch, registers_used, addr_size, expr,
+			      nullptr, per_cu, per_objfile);
 }
diff --git a/gdb/compile/compile.h b/gdb/compile/compile.h
index ca222d2e961..15fc22cb62c 100644
--- a/gdb/compile/compile.h
+++ b/gdb/compile/compile.h
@@ -198,7 +198,7 @@ extern void eval_compile_command (struct command_line *cmd,
 
    ADDR_SIZE is the DWARF address size to use.
 
-   OPT_PTR and OP_END are the bounds of the DWARF expression.
+   EXPR is the DWARF expression.
 
    PER_CU is the per-CU object used for looking up various other
    things.
@@ -213,8 +213,7 @@ extern void compile_dwarf_expr_to_c (string_file *stream,
 				     struct gdbarch *arch,
 				     std::vector<bool> &registers_used,
 				     unsigned int addr_size,
-				     const gdb_byte *op_ptr,
-				     const gdb_byte *op_end,
+				     gdb::array_view<const gdb_byte> expr,
 				     dwarf2_per_cu *per_cu,
 				     dwarf2_per_objfile *per_objfile);
 
@@ -237,7 +236,7 @@ extern void compile_dwarf_expr_to_c (string_file *stream,
 
    ADDR_SIZE is the DWARF address size to use.
 
-   OPT_PTR and OP_END are the bounds of the DWARF expression.
+   EXPR is the DWARF expression.
 
    PER_CU is the per-CU object used for looking up various other
    things.
@@ -252,8 +251,7 @@ extern void compile_dwarf_bounds_to_c (string_file *stream,
 				       struct gdbarch *arch,
 				       std::vector<bool> &registers_used,
 				       unsigned int addr_size,
-				       const gdb_byte *op_ptr,
-				       const gdb_byte *op_end,
+				       gdb::array_view<const gdb_byte> expr,
 				       dwarf2_per_cu *per_cu,
 				       dwarf2_per_objfile *per_objfile);
 
diff --git a/gdb/dwarf2/attribute.h b/gdb/dwarf2/attribute.h
index 653638ee1cc..776ce43825d 100644
--- a/gdb/dwarf2/attribute.h
+++ b/gdb/dwarf2/attribute.h
@@ -33,6 +33,10 @@
 /* Blocks are a bunch of untyped bytes.  */
 struct dwarf_block
 {
+  /* Return the contents of this block.  */
+  gdb::array_view<const gdb_byte> view () const
+  { return gdb::make_array_view (data, size); }
+
   size_t size;
 
   /* Valid only if SIZE is not zero.  */
diff --git a/gdb/dwarf2/call-site.h b/gdb/dwarf2/call-site.h
index 872f48cb662..e5519721390 100644
--- a/gdb/dwarf2/call-site.h
+++ b/gdb/dwarf2/call-site.h
@@ -143,6 +143,15 @@ union call_site_parameter_u
 
 struct call_site_parameter
 {
+  /* Return the DW_AT_call_value DWARF expression.  */
+  gdb::array_view<const gdb_byte> value_expr () const
+  { return gdb::make_array_view (value, value_size); }
+
+  /* Return the DW_AT_call_data_value DWARF expression.  Returns an empty
+     view if not provided by DWARF.  */
+  gdb::array_view<const gdb_byte> data_value_expr () const
+  { return gdb::make_array_view (data_value, data_value_size); }
+
   ENUM_BITFIELD (call_site_parameter_kind) kind : 2;
 
   union call_site_parameter_u u;
diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index 222f563e2a9..38b77f31741 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -783,9 +783,8 @@ dwarf_expr_context::fetch (int n)
 
 /* See expr.h.  */
 
-void
-dwarf_expr_context::get_frame_base (const gdb_byte **start,
-				    size_t * length)
+gdb::array_view<const gdb_byte>
+dwarf_expr_context::get_frame_base ()
 {
   ensure_have_frame (this->m_frame, "DW_OP_fbreg");
 
@@ -804,9 +803,8 @@ dwarf_expr_context::get_frame_base (const gdb_byte **start,
      something has gone wrong.  */
   gdb_assert (framefunc != NULL);
 
-  func_get_frame_base_dwarf_block (framefunc,
-				   get_frame_address_in_block (this->m_frame),
-				   start, length);
+  return func_get_frame_base_dwarf_block
+    (framefunc, get_frame_address_in_block (this->m_frame));
 }
 
 /* See expr.h.  */
@@ -848,7 +846,7 @@ dwarf_expr_context::dwarf_call (cu_offset die_cu_off)
   /* DW_OP_call_ref is currently not supported.  */
   gdb_assert (block.per_cu == this->m_per_cu);
 
-  this->eval (block.data, block.size);
+  this->eval (block.expr ());
 }
 
 /* See expr.h.  */
@@ -921,13 +919,12 @@ dwarf_expr_context::push_dwarf_reg_entry_value (call_site_parameter_kind kind,
     = dwarf_expr_reg_to_entry_parameter (this->m_frame, kind, kind_u,
 					 &caller_per_cu,
 					 &caller_per_objfile);
-  const gdb_byte *data_src
-    = deref_size == -1 ? parameter->value : parameter->data_value;
-  size_t size
-    = deref_size == -1 ? parameter->value_size : parameter->data_value_size;
+  auto expr = (deref_size == -1
+	       ? parameter->value_expr ()
+	       : parameter->data_value_expr ());
 
   /* DEREF_SIZE size is not verified here.  */
-  if (data_src == nullptr)
+  if (expr.empty ())
     throw_error (NO_ENTRY_VALUE_ERROR,
 		 _("Cannot resolve DW_AT_call_data_value"));
 
@@ -949,7 +946,7 @@ dwarf_expr_context::push_dwarf_reg_entry_value (call_site_parameter_kind kind,
   scoped_restore save_addr_size = make_scoped_restore (&this->m_addr_size);
   this->m_addr_size = this->m_per_cu->addr_size ();
 
-  this->eval (data_src, size);
+  this->eval (expr);
 }
 
 /* See expr.h.  */
@@ -1119,8 +1116,8 @@ dwarf_expr_context::fetch_result (struct type *type, struct type *subobj_type,
 /* See expr.h.  */
 
 value *
-dwarf_expr_context::evaluate (const gdb_byte *addr, size_t len, bool as_lval,
-			      dwarf2_per_cu *per_cu,
+dwarf_expr_context::evaluate (gdb::array_view<const gdb_byte> expr,
+			      bool as_lval, dwarf2_per_cu *per_cu,
 			      const frame_info_ptr &frame,
 			      const struct property_addr_info *addr_info,
 			      struct type *type, struct type *subobj_type,
@@ -1130,7 +1127,7 @@ dwarf_expr_context::evaluate (const gdb_byte *addr, size_t len, bool as_lval,
   this->m_frame = frame;
   this->m_addr_info = addr_info;
 
-  eval (addr, len);
+  eval (expr);
   return fetch_result (type, subobj_type, subobj_offset, as_lval);
 }
 
@@ -1285,14 +1282,14 @@ dwarf_expr_context::add_piece (ULONGEST size, ULONGEST offset,
     }
 }
 
-/* Evaluate the expression at ADDR (LEN bytes long).  */
+/* Evaluate the expression EXPR.  */
 
 void
-dwarf_expr_context::eval (const gdb_byte *addr, size_t len)
+dwarf_expr_context::eval (gdb::array_view<const gdb_byte> expr)
 {
   int old_recursion_depth = this->m_recursion_depth;
 
-  execute_stack_op (addr, addr + len);
+  execute_stack_op (expr);
 
   /* RECURSION_DEPTH becomes invalid if an exception was thrown here.  */
 
@@ -1365,13 +1362,15 @@ base_types_equal_p (struct type *t1, struct type *t2)
   return t1->length () == t2->length ();
 }
 
-/* If <BUF..BUF_END] contains DW_FORM_block* with single DW_OP_reg* return the
+/* If BLOCK contains DW_FORM_block* with single DW_OP_reg* return the
    DWARF register number.  Otherwise return -1.  */
 
 int
-dwarf_block_to_dwarf_reg (const gdb_byte *buf, const gdb_byte *buf_end)
+dwarf_block_to_dwarf_reg (gdb::array_view<const gdb_byte> block)
 {
   uint64_t dwarf_reg;
+  const gdb_byte *buf = block.data ();
+  const gdb_byte *const buf_end = block.data () + block.size ();
 
   if (buf_end <= buf)
     return -1;
@@ -1406,17 +1405,19 @@ dwarf_block_to_dwarf_reg (const gdb_byte *buf, const gdb_byte *buf_end)
   return dwarf_reg;
 }
 
-/* If <BUF..BUF_END] contains DW_FORM_block* with just DW_OP_breg*(0) and
-   DW_OP_deref* return the DWARF register number.  Otherwise return -1.
-   DEREF_SIZE_RETURN contains -1 for DW_OP_deref; otherwise it contains the
-   size from DW_OP_deref_size.  */
+/* If BLOCK contains DW_FORM_block* with just DW_OP_breg*(0) and DW_OP_deref*
+   return the DWARF register number.  Otherwise return -1.  DEREF_SIZE_RETURN
+   contains -1 for DW_OP_deref; otherwise it contains the size from
+   DW_OP_deref_size.  */
 
 int
-dwarf_block_to_dwarf_reg_deref (const gdb_byte *buf, const gdb_byte *buf_end,
+dwarf_block_to_dwarf_reg_deref (gdb::array_view<const gdb_byte> block,
 				CORE_ADDR *deref_size_return)
 {
   uint64_t dwarf_reg;
   int64_t offset;
+  const gdb_byte *buf = block.data ();
+  const gdb_byte *const buf_end = block.data () + block.size ();
 
   if (buf_end <= buf)
     return -1;
@@ -1470,10 +1471,12 @@ dwarf_block_to_dwarf_reg_deref (const gdb_byte *buf, const gdb_byte *buf_end,
 /* See expr.h.  */
 
 bool
-dwarf_block_to_fb_offset (const gdb_byte *buf, const gdb_byte *buf_end,
+dwarf_block_to_fb_offset (gdb::array_view<const gdb_byte> block,
 			  CORE_ADDR *fb_offset_return)
 {
   int64_t fb_offset;
+  const gdb_byte *buf = block.data ();
+  const gdb_byte *const buf_end = block.data () + block.size ();
 
   if (buf_end <= buf)
     return false;
@@ -1495,11 +1498,14 @@ dwarf_block_to_fb_offset (const gdb_byte *buf, const gdb_byte *buf_end,
 /* See expr.h.  */
 
 bool
-dwarf_block_to_sp_offset (struct gdbarch *gdbarch, const gdb_byte *buf,
-			  const gdb_byte *buf_end, CORE_ADDR *sp_offset_return)
+dwarf_block_to_sp_offset (struct gdbarch *gdbarch,
+			  gdb::array_view<const gdb_byte> block,
+			  CORE_ADDR *sp_offset_return)
 {
   uint64_t dwarf_reg;
   int64_t sp_offset;
+  const gdb_byte *buf = block.data ();
+  const gdb_byte *const buf_end = block.data () + block.size ();
 
   if (buf_end <= buf)
     return false;
@@ -1555,11 +1561,10 @@ trivial_entry_value (frame_info_ptr frame)
 }
 
 /* The engine for the expression evaluator.  Using the context in this
-   object, evaluate the expression between OP_PTR and OP_END.  */
+   object, evaluate the expression EXPR.  */
 
 void
-dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
-				      const gdb_byte *op_end)
+dwarf_expr_context::execute_stack_op (gdb::array_view<const gdb_byte> expr)
 {
   gdbarch *arch = this->m_per_objfile->objfile->arch ();
   bfd_endian byte_order = gdbarch_byte_order (arch);
@@ -1580,6 +1585,9 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 	   this->m_recursion_depth);
   this->m_recursion_depth++;
 
+  const gdb_byte *op_ptr = expr.data ();
+  const gdb_byte *op_end = expr.data () + expr.size ();
+
   while (op_ptr < op_end)
     {
       dwarf_location_atom op = (dwarf_location_atom) *op_ptr++;
@@ -1880,9 +1888,6 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 	  break;
 	case DW_OP_fbreg:
 	  {
-	    const gdb_byte *datastart;
-	    size_t datalen;
-
 	    op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
 
 	    /* Rather than create a whole new context, we simply
@@ -1895,8 +1900,7 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 	    /* FIXME: cagney/2003-03-26: This code should be using
 	       get_frame_base_address(), and then implement a dwarf2
 	       specific this_base method.  */
-	    this->get_frame_base (&datastart, &datalen);
-	    eval (datastart, datalen);
+	    eval (this->get_frame_base ());
 	    if (this->m_location == DWARF_VALUE_MEMORY)
 	      result = fetch_address (0);
 	    else if (this->m_location == DWARF_VALUE_REGISTER)
@@ -2310,7 +2314,8 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 	    if (op_ptr + len > op_end)
 	      error (_("DW_OP_entry_value: too few bytes available."));
 
-	    kind_u.dwarf_reg = dwarf_block_to_dwarf_reg (op_ptr, op_ptr + len);
+	    auto entry_value_expr = gdb::make_array_view (op_ptr, len);
+	    kind_u.dwarf_reg = dwarf_block_to_dwarf_reg (entry_value_expr);
 	    if (kind_u.dwarf_reg != -1)
 	      {
 		op_ptr += len;
@@ -2331,8 +2336,7 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 		goto no_push;
 	      }
 
-	    kind_u.dwarf_reg = dwarf_block_to_dwarf_reg_deref (op_ptr,
-							       op_ptr + len,
+	    kind_u.dwarf_reg = dwarf_block_to_dwarf_reg_deref (entry_value_expr,
 							       &deref_size);
 	    if (kind_u.dwarf_reg != -1)
 	      {
diff --git a/gdb/dwarf2/expr.h b/gdb/dwarf2/expr.h
index eaa16693534..02b0e41f6fd 100644
--- a/gdb/dwarf2/expr.h
+++ b/gdb/dwarf2/expr.h
@@ -129,8 +129,7 @@ struct dwarf_expr_context
 
   void push_address (CORE_ADDR value, bool in_stack_memory);
 
-  /* Evaluate the expression at ADDR (LEN bytes long) in a given PER_CU
-     and FRAME context.
+  /* Evaluate expression EXPR in a given PER_CU and FRAME context.
 
      AS_LVAL defines if the returned struct value is expected to be a
      value (false) or a location description (true).
@@ -140,7 +139,7 @@ struct dwarf_expr_context
 
      The ADDR_INFO property can be specified to override the range of
      memory addresses with the passed in buffer.  */
-  value *evaluate (const gdb_byte *addr, size_t len, bool as_lval,
+  value *evaluate (gdb::array_view<const gdb_byte> expr, bool as_lval,
 		   dwarf2_per_cu *per_cu, const frame_info_ptr &frame,
 		   const struct property_addr_info *addr_info = nullptr,
 		   struct type *type = nullptr,
@@ -208,12 +207,12 @@ private:
   /* Property address info used for the evaluation.  */
   const struct property_addr_info *m_addr_info = nullptr;
 
-  void eval (const gdb_byte *addr, size_t len);
+  void eval (gdb::array_view<const gdb_byte> expr);
   struct type *address_type () const;
   void push (struct value *value, bool in_stack_memory);
   bool stack_empty_p () const;
   void add_piece (ULONGEST size, ULONGEST offset, enum dwarf_location_atom op);
-  void execute_stack_op (const gdb_byte *op_ptr, const gdb_byte *op_end);
+  void execute_stack_op (gdb::array_view<const gdb_byte> expr);
   void pop ();
   struct value *fetch (int n);
   CORE_ADDR fetch_address (int n);
@@ -227,10 +226,10 @@ private:
   value *fetch_result (struct type *type, struct type *subobj_type,
 		       LONGEST subobj_offset, bool as_lval);
 
-  /* Return the location expression for the frame base attribute, in
-     START and LENGTH.  The result must be live until the current
-     expression evaluation is complete.  */
-  void get_frame_base (const gdb_byte **start, size_t *length);
+  /* Return the location expression for the frame base attribute.  The
+     result must be live until the current expression evaluation is
+     complete.  */
+  gdb::array_view<const gdb_byte> get_frame_base ();
 
   /* Return the base type given by the indicated DIE at DIE_CU_OFF.
      This can throw an exception if the DIE is invalid or does not
@@ -269,25 +268,24 @@ CORE_ADDR read_addr_from_reg (const frame_info_ptr &frame, int reg);
 void dwarf_expr_require_composition (const gdb_byte *, const gdb_byte *,
 				     const char *);
 
-int dwarf_block_to_dwarf_reg (const gdb_byte *buf, const gdb_byte *buf_end);
+int dwarf_block_to_dwarf_reg (gdb::array_view<const gdb_byte> block);
 
-int dwarf_block_to_dwarf_reg_deref (const gdb_byte *buf,
-				    const gdb_byte *buf_end,
+int dwarf_block_to_dwarf_reg_deref (gdb::array_view<const gdb_byte> block,
 				    CORE_ADDR *deref_size_return);
 
-/* If <BUF..BUF_END] contains DW_FORM_block* with single DW_OP_fbreg(X) fill
-   in FB_OFFSET_RETURN with the X offset and return true.  Otherwise return
+/* If BLOCK contains DW_FORM_block* with single DW_OP_fbreg(X) fill in
+   FB_OFFSET_RETURN with the X offset and return true.  Otherwise return
    false.  */
 
-bool dwarf_block_to_fb_offset (const gdb_byte *buf, const gdb_byte *buf_end,
+bool dwarf_block_to_fb_offset (gdb::array_view<const gdb_byte> block,
 			       CORE_ADDR *fb_offset_return);
 
-/* If <BUF..BUF_END] contains DW_FORM_block* with single DW_OP_bregSP(X) fill
-   in SP_OFFSET_RETURN with the X offset and return true.  Otherwise return
+/* If BLOCK contains DW_FORM_block* with single DW_OP_bregSP(X) fill in
+   SP_OFFSET_RETURN with the X offset and return true.  Otherwise return
    false.  The matched SP register number depends on GDBARCH.  */
 
-bool dwarf_block_to_sp_offset (struct gdbarch *gdbarch, const gdb_byte *buf,
-			       const gdb_byte *buf_end,
+bool dwarf_block_to_sp_offset (struct gdbarch *gdbarch,
+			       gdb::array_view<const gdb_byte> block,
 			       CORE_ADDR *sp_offset_return);
 
 /* Wrappers around the leb128 reader routines to simplify them for our
diff --git a/gdb/dwarf2/frame.c b/gdb/dwarf2/frame.c
index 70895e90696..5b9f41cd53a 100644
--- a/gdb/dwarf2/frame.c
+++ b/gdb/dwarf2/frame.c
@@ -183,11 +183,6 @@ static ULONGEST read_encoded_value (struct comp_unit *unit, gdb_byte encoding,
 				    int ptr_len, const gdb_byte *buf,
 				    unsigned int *bytes_read_ptr,
 				    unrelocated_addr func_base);
-
-
-/* Store the length the expression for the CFA in the `cfa_reg' field,
-   which is unused in that case.  */
-#define cfa_exp_len cfa_reg
 
 dwarf2_frame_state::dwarf2_frame_state (CORE_ADDR pc_, struct dwarf2_cie *cie)
   : pc (pc_), data_align (cie->data_alignment_factor),
@@ -228,7 +223,7 @@ register %s (#%d) at %s"),
 }
 
 static CORE_ADDR
-execute_stack_op (const gdb_byte *exp, ULONGEST len, int addr_size,
+execute_stack_op (gdb::array_view<const gdb_byte> expr, int addr_size,
 		  const frame_info_ptr &this_frame, CORE_ADDR initial,
 		  int initial_in_stack_memory, dwarf2_per_objfile *per_objfile)
 {
@@ -236,7 +231,7 @@ execute_stack_op (const gdb_byte *exp, ULONGEST len, int addr_size,
   scoped_value_mark free_values;
 
   ctx.push_address (initial, initial_in_stack_memory);
-  value *result_val = ctx.evaluate (exp, len, true, nullptr, this_frame);
+  value *result_val = ctx.evaluate (expr, true, nullptr, this_frame);
 
   if (result_val->lval () == lval_memory)
     return result_val->address ();
@@ -408,10 +403,9 @@ bad CFI data; mismatched DW_CFA_restore_state at %s"),
 
 	    case DW_CFA_def_cfa_expression:
 	      insn_ptr = safe_read_uleb128 (insn_ptr, insn_end, &utmp);
-	      fs->regs.cfa_exp_len = utmp;
-	      fs->regs.cfa_exp = insn_ptr;
+	      fs->regs.cfa_exp = gdb::make_array_view (insn_ptr, utmp);
 	      fs->regs.cfa_how = CFA_EXP;
-	      insn_ptr += fs->regs.cfa_exp_len;
+	      insn_ptr += utmp;
 	      break;
 
 	    case DW_CFA_expression:
@@ -571,7 +565,7 @@ execute_cfa_program_test (struct gdbarch *gdbarch)
   SELF_CHECK (fs.regs.cfa_reg == 1);
   SELF_CHECK (fs.regs.cfa_offset == 4);
   SELF_CHECK (fs.regs.cfa_how == CFA_REG_OFFSET);
-  SELF_CHECK (fs.regs.cfa_exp == NULL);
+  SELF_CHECK (fs.regs.cfa_exp.empty ());
   SELF_CHECK (fs.regs.prev == NULL);
 }
 
@@ -759,8 +753,7 @@ bool
 dwarf2_fetch_cfa_info (struct gdbarch *gdbarch, CORE_ADDR pc,
 		       dwarf2_per_cu *data, int *regnum_out,
 		       LONGEST *offset_out, CORE_ADDR *text_offset_out,
-		       const gdb_byte **cfa_start_out,
-		       const gdb_byte **cfa_end_out)
+		       gdb::array_view<const gdb_byte> &cfa_expr_out)
 {
   struct dwarf2_fde *fde;
   dwarf2_per_objfile *per_objfile;
@@ -811,8 +804,7 @@ dwarf2_fetch_cfa_info (struct gdbarch *gdbarch, CORE_ADDR pc,
 
     case CFA_EXP:
       *text_offset_out = per_objfile->objfile->text_section_offset ();
-      *cfa_start_out = fs.regs.cfa_exp;
-      *cfa_end_out = fs.regs.cfa_exp + fs.regs.cfa_exp_len;
+      cfa_expr_out = fs.regs.cfa_exp;
       return false;
 
     default:
@@ -978,10 +970,8 @@ dwarf2_frame_cache (const frame_info_ptr &this_frame, void **this_cache)
 	  break;
 
 	case CFA_EXP:
-	  cache->cfa =
-	    execute_stack_op (fs.regs.cfa_exp, fs.regs.cfa_exp_len,
-			      cache->addr_size, this_frame, 0, 0,
-			      cache->per_objfile);
+	  cache->cfa = execute_stack_op (fs.regs.cfa_exp, cache->addr_size,
+					 this_frame, 0, 0, cache->per_objfile);
 	  break;
 
 	default:
@@ -1166,10 +1156,8 @@ dwarf2_frame_prev_register (const frame_info_ptr &this_frame, void **this_cache,
       return frame_unwind_got_register (this_frame, regnum, realnum);
 
     case DWARF2_FRAME_REG_SAVED_EXP:
-      addr = execute_stack_op (cache->reg[regnum].loc.exp.start,
-			       cache->reg[regnum].loc.exp.len,
-			       cache->addr_size,
-			       this_frame, cache->cfa, 1,
+      addr = execute_stack_op (cache->reg[regnum].loc.exp.view (),
+			       cache->addr_size, this_frame, cache->cfa, 1,
 			       cache->per_objfile);
       return frame_unwind_got_memory (this_frame, regnum, addr);
 
@@ -1178,10 +1166,8 @@ dwarf2_frame_prev_register (const frame_info_ptr &this_frame, void **this_cache,
       return frame_unwind_got_constant (this_frame, regnum, addr);
 
     case DWARF2_FRAME_REG_SAVED_VAL_EXP:
-      addr = execute_stack_op (cache->reg[regnum].loc.exp.start,
-			       cache->reg[regnum].loc.exp.len,
-			       cache->addr_size,
-			       this_frame, cache->cfa, 1,
+      addr = execute_stack_op (cache->reg[regnum].loc.exp.view (),
+			       cache->addr_size, this_frame, cache->cfa, 1,
 			       cache->per_objfile);
       return frame_unwind_got_constant (this_frame, regnum, addr);
 
diff --git a/gdb/dwarf2/frame.h b/gdb/dwarf2/frame.h
index 6ecd5d0d656..d3c71c3d16e 100644
--- a/gdb/dwarf2/frame.h
+++ b/gdb/dwarf2/frame.h
@@ -78,6 +78,10 @@ struct dwarf2_frame_state_reg
     ULONGEST reg;
     struct
     {
+      /* Return this expression.  */
+      gdb::array_view<const gdb_byte> view () const
+      { return gdb::make_array_view (start, len); }
+
       const gdb_byte *start;
       ULONGEST len;
     } exp;
@@ -143,7 +147,7 @@ struct dwarf2_frame_state_reg_info
   LONGEST cfa_offset = 0;
   ULONGEST cfa_reg = 0;
   enum cfa_how_kind cfa_how = CFA_UNSET;
-  const gdb_byte *cfa_exp = NULL;
+  gdb::array_view<const gdb_byte> cfa_exp;
 
   /* Used to implement DW_CFA_remember_state.  */
   struct dwarf2_frame_state_reg_info *prev = NULL;
@@ -255,15 +259,13 @@ CORE_ADDR dwarf2_frame_cfa (const frame_info_ptr &this_frame);
    OFFSET_OUT is the offset to use from this register.
    These are only filled in when true is returned.
 
-   TEXT_OFFSET_OUT, CFA_START_OUT, and CFA_END_OUT describe the CFA
-   in other cases.  These are only used when false is returned.  */
+   TEXT_OFFSET_OUT and CFA_EXPR describe the CFA in other cases.  These are
+   only filled in when false is returned.  */
 
-extern bool dwarf2_fetch_cfa_info (struct gdbarch *gdbarch, CORE_ADDR pc,
-				   dwarf2_per_cu *data, int *regnum_out,
-				   LONGEST *offset_out,
-				   CORE_ADDR *text_offset_out,
-				   const gdb_byte **cfa_start_out,
-				   const gdb_byte **cfa_end_out);
+extern bool dwarf2_fetch_cfa_info
+  (struct gdbarch *gdbarch, CORE_ADDR pc, dwarf2_per_cu *data, int *regnum_out,
+   LONGEST *offset_out, CORE_ADDR *text_offset_out,
+   gdb::array_view<const gdb_byte> &cfa_expr_out);
 
 /* Allocate a new instance of the function unique data.
 
diff --git a/gdb/dwarf2/loc.c b/gdb/dwarf2/loc.c
index a493a46dcfc..5bf863e13d5 100644
--- a/gdb/dwarf2/loc.c
+++ b/gdb/dwarf2/loc.c
@@ -49,9 +49,10 @@
 #include "extract-store-integer.h"
 
 static struct value *dwarf2_evaluate_loc_desc_full
-  (struct type *type, const frame_info_ptr &frame, const gdb_byte *data,
-   size_t size, dwarf2_per_cu *per_cu, dwarf2_per_objfile *per_objfile,
-   struct type *subobj_type, LONGEST subobj_byte_offset, bool as_lval = true);
+  (struct type *type, const frame_info_ptr &frame,
+   gdb::array_view<const gdb_byte> loc_desc, dwarf2_per_cu *per_cu,
+   dwarf2_per_objfile *per_objfile, struct type *subobj_type,
+   LONGEST subobj_byte_offset, bool as_lval = true);
 
 /* Until these have formal names, we define these here.
    ref: http://gcc.gnu.org/wiki/DebugFission
@@ -354,18 +355,16 @@ decode_debug_loc_dwo_addresses (dwarf2_per_cu *per_cu,
     }
 }
 
-/* A function for dealing with location lists.  Given a
-   symbol baton (BATON) and a pc value (PC), find the appropriate
-   location expression, set *LOCEXPR_LENGTH, and return a pointer
-   to the beginning of the expression.  Returns NULL on failure.
+/* A function for dealing with location lists.  Given a symbol baton
+   (BATON) and a pc value (PC), find and return the appropriate location
+   expression.  Returns an empty view on failure.
 
    For now, only return the first matching location expression; there
    can be more than one in the list.  */
 
-const gdb_byte *
+gdb::array_view<const gdb_byte>
 dwarf2_find_location_expression (const dwarf2_loclist_baton *baton,
-				 size_t *locexpr_length, const CORE_ADDR pc,
-				 bool at_entry)
+				 const CORE_ADDR pc, bool at_entry)
 {
   dwarf2_per_objfile *per_objfile = baton->per_objfile;
   struct objfile *objfile = per_objfile->objfile;
@@ -410,8 +409,7 @@ dwarf2_find_location_expression (const dwarf2_loclist_baton *baton,
       switch (kind)
 	{
 	case DEBUG_LOC_END_OF_LIST:
-	  *locexpr_length = 0;
-	  return NULL;
+	  return {};
 
 	case DEBUG_LOC_BASE_ADDRESS:
 	  base_address = high;
@@ -470,17 +468,11 @@ dwarf2_find_location_expression (const dwarf2_loclist_baton *baton,
 	    pc_func = pc_block->linkage_function ();
 
 	  if (pc_func && pc == pc_func->value_block ()->entry_pc ())
-	    {
-	      *locexpr_length = length;
-	      return loc_ptr;
-	    }
+	    return gdb::make_array_view (loc_ptr, length);
 	}
 
       if (unrel_pc >= low && unrel_pc < high)
-	{
-	  *locexpr_length = length;
-	  return loc_ptr;
-	}
+	return gdb::make_array_view (loc_ptr, length);
 
       loc_ptr += length;
     }
@@ -489,15 +481,13 @@ dwarf2_find_location_expression (const dwarf2_loclist_baton *baton,
 /* Implement find_frame_base_location method for LOC_BLOCK functions using
    DWARF expression for its DW_AT_frame_base.  */
 
-static void
-locexpr_find_frame_base_location (struct symbol *framefunc, CORE_ADDR pc,
-				  const gdb_byte **start, size_t *length)
+static gdb::array_view<const gdb_byte>
+locexpr_find_frame_base_location (struct symbol *framefunc, CORE_ADDR pc)
 {
   struct dwarf2_locexpr_baton *symbaton
     = (struct dwarf2_locexpr_baton *) SYMBOL_LOCATION_BATON (framefunc);
 
-  *length = symbaton->size;
-  *start = symbaton->data;
+  return symbaton->expr ();
 }
 
 /* Implement the struct symbol_block_ops::get_frame_base method for
@@ -509,8 +499,6 @@ locexpr_get_frame_base (struct symbol *framefunc, const frame_info_ptr &frame)
   struct gdbarch *gdbarch;
   struct type *type;
   struct dwarf2_locexpr_baton *dlbaton;
-  const gdb_byte *start;
-  size_t length;
   struct value *result;
 
   /* If this method is called, then FRAMEFUNC is supposed to be a DWARF block.
@@ -522,11 +510,11 @@ locexpr_get_frame_base (struct symbol *framefunc, const frame_info_ptr &frame)
   type = builtin_type (gdbarch)->builtin_data_ptr;
   dlbaton = (struct dwarf2_locexpr_baton *) SYMBOL_LOCATION_BATON (framefunc);
 
-  framefunc->block_ops ()->find_frame_base_location (framefunc,
-						     get_frame_pc (frame),
-						     &start, &length);
-  result = dwarf2_evaluate_loc_desc (type, frame, start, length,
-				     dlbaton->per_cu, dlbaton->per_objfile);
+  auto expr
+    = framefunc->block_ops ()->find_frame_base_location (framefunc,
+							 get_frame_pc (frame));
+  result = dwarf2_evaluate_loc_desc (type, frame, expr, dlbaton->per_cu,
+				     dlbaton->per_objfile);
 
   /* The DW_AT_frame_base attribute contains a location description which
      computes the base address itself.  However, the call to
@@ -548,14 +536,13 @@ const struct symbol_block_ops dwarf2_block_frame_base_locexpr_funcs =
 /* Implement find_frame_base_location method for LOC_BLOCK functions using
    DWARF location list for its DW_AT_frame_base.  */
 
-static void
-loclist_find_frame_base_location (struct symbol *framefunc, CORE_ADDR pc,
-				  const gdb_byte **start, size_t *length)
+static gdb::array_view<const gdb_byte>
+loclist_find_frame_base_location (struct symbol *framefunc, CORE_ADDR pc)
 {
   struct dwarf2_loclist_baton *symbaton
     = (struct dwarf2_loclist_baton *) SYMBOL_LOCATION_BATON (framefunc);
 
-  *start = dwarf2_find_location_expression (symbaton, length, pc);
+  return dwarf2_find_location_expression (symbaton, pc);
 }
 
 /* Implement the struct symbol_block_ops::get_frame_base method for
@@ -567,8 +554,6 @@ loclist_get_frame_base (struct symbol *framefunc, const frame_info_ptr &frame)
   struct gdbarch *gdbarch;
   struct type *type;
   struct dwarf2_loclist_baton *dlbaton;
-  const gdb_byte *start;
-  size_t length;
   struct value *result;
 
   /* If this method is called, then FRAMEFUNC is supposed to be a DWARF block.
@@ -580,11 +565,11 @@ loclist_get_frame_base (struct symbol *framefunc, const frame_info_ptr &frame)
   type = builtin_type (gdbarch)->builtin_data_ptr;
   dlbaton = (struct dwarf2_loclist_baton *) SYMBOL_LOCATION_BATON (framefunc);
 
-  framefunc->block_ops ()->find_frame_base_location (framefunc,
-						     get_frame_pc (frame),
-						     &start, &length);
-  result = dwarf2_evaluate_loc_desc (type, frame, start, length,
-				     dlbaton->per_cu, dlbaton->per_objfile);
+  auto expr
+    = framefunc->block_ops ()->find_frame_base_location (framefunc,
+							 get_frame_pc (frame));
+  result = dwarf2_evaluate_loc_desc (type, frame, expr, dlbaton->per_cu,
+				     dlbaton->per_objfile);
 
   /* The DW_AT_frame_base attribute contains a location description which
      computes the base address itself.  However, the call to
@@ -605,19 +590,20 @@ const struct symbol_block_ops dwarf2_block_frame_base_loclist_funcs =
 
 /* See dwarf2/loc.h.  */
 
-void
-func_get_frame_base_dwarf_block (struct symbol *framefunc, CORE_ADDR pc,
-				 const gdb_byte **start, size_t *length)
+gdb::array_view<const gdb_byte>
+func_get_frame_base_dwarf_block (struct symbol *framefunc, CORE_ADDR pc)
 {
+  gdb::array_view<const gdb_byte> block;
+
   if (const symbol_block_ops *block_ops = framefunc->block_ops ();
       block_ops != nullptr)
-    block_ops->find_frame_base_location (framefunc, pc, start, length);
-  else
-    *length = 0;
+    block = block_ops->find_frame_base_location (framefunc, pc);
 
-  if (*length == 0)
+  if (block.empty ())
     error (_("Could not find the frame base for \"%s\"."),
 	   framefunc->natural_name ());
+
+  return block;
 }
 
 /* See loc.h.  */
@@ -692,7 +678,7 @@ call_site_target::iterate_over_addresses (gdbarch *call_site_gdbarch,
 	caller_arch = get_frame_arch (caller_frame);
 	caller_core_addr_type = builtin_type (caller_arch)->builtin_func_ptr;
 	val = dwarf2_evaluate_loc_desc (caller_core_addr_type, caller_frame,
-					dwarf_block->data, dwarf_block->size,
+					dwarf_block->expr (),
 					dwarf_block->per_cu,
 					dwarf_block->per_objfile);
 	/* DW_AT_call_target is a DWARF expression, not a DWARF location.  */
@@ -1275,8 +1261,9 @@ dwarf_entry_parameter_to_value (struct call_site_parameter *parameter,
     throw_error (NO_ENTRY_VALUE_ERROR,
 		 _("Cannot resolve DW_AT_call_data_value"));
 
-  return dwarf2_evaluate_loc_desc (type, caller_frame, data_src, size, per_cu,
-				   per_objfile, false);
+  return dwarf2_evaluate_loc_desc (type, caller_frame,
+				   gdb::make_array_view (data_src, size),
+				   per_cu, per_objfile, false);
 }
 
 /* VALUE must be of type lval_computed with entry_data_value_funcs.  Perform
@@ -1384,8 +1371,8 @@ value_of_dwarf_reg_entry (struct type *type, const frame_info_ptr &frame,
   return val;
 }
 
-/* Read parameter of TYPE at (callee) FRAME's function entry.  DATA and
-   SIZE are DWARF block used to match DW_AT_location at the caller's
+/* Read parameter of TYPE at (callee) FRAME's function entry.  BLOCK is the
+   DWARF block used to match DW_AT_location at the caller's
    DW_TAG_call_site_parameter.
 
    Function always returns non-NULL value.  It throws NO_ENTRY_VALUE_ERROR if it
@@ -1393,16 +1380,16 @@ value_of_dwarf_reg_entry (struct type *type, const frame_info_ptr &frame,
 
 static struct value *
 value_of_dwarf_block_entry (struct type *type, const frame_info_ptr &frame,
-			    const gdb_byte *block, size_t block_len)
+			    gdb::array_view<const gdb_byte> block)
 {
   union call_site_parameter_u kind_u;
 
-  kind_u.dwarf_reg = dwarf_block_to_dwarf_reg (block, block + block_len);
+  kind_u.dwarf_reg = dwarf_block_to_dwarf_reg (block);
   if (kind_u.dwarf_reg != -1)
     return value_of_dwarf_reg_entry (type, frame, CALL_SITE_PARAMETER_DWARF_REG,
 				     kind_u);
 
-  if (dwarf_block_to_fb_offset (block, block + block_len, &kind_u.fb_offset))
+  if (dwarf_block_to_fb_offset (block, &kind_u.fb_offset))
     return value_of_dwarf_reg_entry (type, frame, CALL_SITE_PARAMETER_FB_OFFSET,
 				     kind_u);
 
@@ -1475,26 +1462,24 @@ indirect_synthetic_pointer (sect_offset die, LONGEST byte_offset,
   /* If pointed-to DIE has a DW_AT_location, evaluate it and return the
      resulting value.  Otherwise, it may have a DW_AT_const_value instead,
      or it may've been optimized out.  */
-  if (baton.data != NULL)
-    return dwarf2_evaluate_loc_desc_full (orig_type, frame, baton.data,
-					  baton.size, baton.per_cu,
+  auto expr = baton.expr ();
+  if (!expr.empty ())
+    return dwarf2_evaluate_loc_desc_full (orig_type, frame, expr, baton.per_cu,
 					  baton.per_objfile,
-					  type->target_type (),
-					  byte_offset);
+					  type->target_type (), byte_offset);
   else
     return fetch_const_value_from_synthetic_pointer (die, byte_offset, per_cu,
 						     per_objfile, type);
 }
 
-/* Evaluate a location description, starting at DATA and with length
-   SIZE, to find the current location of variable of TYPE in the
-   context of FRAME.  If SUBOBJ_TYPE is non-NULL, return instead the
-   location of the subobject of type SUBOBJ_TYPE at byte offset
-   SUBOBJ_BYTE_OFFSET within the variable of type TYPE.  */
+/* Evaluate the location description LOC_DESC to find the current location
+   of variable of TYPE in the context of FRAME.  If SUBOBJ_TYPE is non-NULL,
+   return instead the location of the subobject of type SUBOBJ_TYPE at byte
+   offset SUBOBJ_BYTE_OFFSET within the variable of type TYPE.  */
 
 static struct value *
 dwarf2_evaluate_loc_desc_full (struct type *type, const frame_info_ptr &frame,
-			       const gdb_byte *data, size_t size,
+			       gdb::array_view<const gdb_byte> loc_desc,
 			       dwarf2_per_cu *per_cu,
 			       dwarf2_per_objfile *per_objfile,
 			       struct type *subobj_type,
@@ -1509,7 +1494,7 @@ dwarf2_evaluate_loc_desc_full (struct type *type, const frame_info_ptr &frame,
   else if (subobj_byte_offset < 0)
     invalid_synthetic_pointer ();
 
-  if (size == 0)
+  if (loc_desc.empty ())
     return value::allocate_optimized_out (subobj_type);
 
   dwarf_expr_context ctx (per_objfile, per_cu->addr_size ());
@@ -1519,7 +1504,7 @@ dwarf2_evaluate_loc_desc_full (struct type *type, const frame_info_ptr &frame,
 
   try
     {
-      retval = ctx.evaluate (data, size, as_lval, per_cu, frame, nullptr,
+      retval = ctx.evaluate (loc_desc, as_lval, per_cu, frame, nullptr,
 			     type, subobj_type, subobj_byte_offset);
     }
   catch (const gdb_exception_error &ex)
@@ -1559,11 +1544,11 @@ dwarf2_evaluate_loc_desc_full (struct type *type, const frame_info_ptr &frame,
 
 struct value *
 dwarf2_evaluate_loc_desc (struct type *type, const frame_info_ptr &frame,
-			  const gdb_byte *data, size_t size,
+			  gdb::array_view<const gdb_byte> loc_desc,
 			  dwarf2_per_cu *per_cu,
 			  dwarf2_per_objfile *per_objfile, bool as_lval)
 {
-  return dwarf2_evaluate_loc_desc_full (type, frame, data, size, per_cu,
+  return dwarf2_evaluate_loc_desc_full (type, frame, loc_desc, per_cu,
 					per_objfile, NULL, 0, as_lval);
 }
 
@@ -1603,8 +1588,8 @@ dwarf2_locexpr_baton_eval (const struct dwarf2_locexpr_baton *dlbaton,
 
   try
     {
-      result = ctx.evaluate (dlbaton->data, dlbaton->size,
-			     true, per_cu, frame, addr_stack);
+      result = ctx.evaluate (dlbaton->expr (), true, per_cu, frame,
+			     addr_stack);
     }
   catch (const gdb_exception_error &ex)
     {
@@ -1704,19 +1689,17 @@ dwarf2_evaluate_property (const dynamic_prop *prop,
       {
 	const dwarf2_property_baton *baton = prop->baton ();
 	CORE_ADDR pc;
-	const gdb_byte *data;
 	struct value *val;
-	size_t size;
 
 	if (frame == NULL
 	    || !get_frame_address_in_block_if_available (frame, &pc))
 	  return false;
 
-	data = dwarf2_find_location_expression (&baton->loclist, &size, pc);
-	if (data != NULL)
+	auto data = dwarf2_find_location_expression (&baton->loclist, pc);
+	if (!data.empty ())
 	  {
 	    val = dwarf2_evaluate_loc_desc (baton->property_type, frame, data,
-					    size, baton->loclist.per_cu,
+					    baton->loclist.per_cu,
 					    baton->loclist.per_objfile);
 	    if (!val->optimized_out ())
 	      {
@@ -1809,15 +1792,13 @@ dwarf2_compile_property_to_c (string_file *stream,
 {
 #if defined (HAVE_COMPILE)
   const dwarf2_property_baton *baton = prop->baton ();
-  const gdb_byte *data;
-  size_t size;
+  gdb::array_view<const gdb_byte> expr;
   dwarf2_per_cu *per_cu;
   dwarf2_per_objfile *per_objfile;
 
   if (prop->kind () == PROP_LOCEXPR)
     {
-      data = baton->locexpr.data;
-      size = baton->locexpr.size;
+      expr = baton->locexpr.expr ();
       per_cu = baton->locexpr.per_cu;
       per_objfile = baton->locexpr.per_objfile;
     }
@@ -1825,15 +1806,14 @@ dwarf2_compile_property_to_c (string_file *stream,
     {
       gdb_assert (prop->kind () == PROP_LOCLIST);
 
-      data = dwarf2_find_location_expression (&baton->loclist, &size, pc);
+      expr = dwarf2_find_location_expression (&baton->loclist, pc);
       per_cu = baton->loclist.per_cu;
       per_objfile = baton->loclist.per_objfile;
     }
 
-  compile_dwarf_bounds_to_c (stream, result_name, prop, sym, pc,
-			     gdbarch, registers_used,
-			     per_cu->addr_size (),
-			     data, data + size, per_cu, per_objfile);
+  compile_dwarf_bounds_to_c (stream, result_name, prop, sym, pc, gdbarch,
+			     registers_used, per_cu->addr_size (), expr,
+			     per_cu, per_objfile);
 #else
   gdb_assert_not_reached ("Compile support was disabled");
 #endif
@@ -2185,10 +2165,8 @@ dwarf2_get_symbol_read_needs (gdb::array_view<const gdb_byte> expr,
 	    if (symbol_needs != SYMBOL_NEEDS_FRAME)
 	      {
 		gdbarch *arch = baton.per_objfile->objfile->arch ();
-		gdb::array_view<const gdb_byte> sub_expr (baton.data,
-							  baton.size);
 		symbol_needs
-		  = dwarf2_get_symbol_read_needs (sub_expr,
+		  = dwarf2_get_symbol_read_needs (baton.expr (),
 						  baton.per_cu,
 						  baton.per_objfile,
 						  gdbarch_byte_order (arch),
@@ -2238,10 +2216,8 @@ dwarf2_get_symbol_read_needs (gdb::array_view<const gdb_byte> expr,
 	    if (symbol_needs != SYMBOL_NEEDS_FRAME)
 	      {
 		gdbarch *arch = baton.per_objfile->objfile->arch ();
-		gdb::array_view<const gdb_byte> sub_expr (baton.data,
-							  baton.size);
 		symbol_needs
-		  = dwarf2_get_symbol_read_needs (sub_expr,
+		  = dwarf2_get_symbol_read_needs (baton.expr (),
 						  baton.per_cu,
 						  baton.per_objfile,
 						  gdbarch_byte_order (arch),
@@ -2391,37 +2367,39 @@ access_memory (struct gdbarch *arch, struct agent_expr *expr, ULONGEST nbits)
 
 /* Compile a DWARF location expression to an agent expression.
 
-   EXPR is the agent expression we are building.
+   AX is the agent expression we are building.
    LOC is the agent value we modify.
-   ARCH is the architecture.
    ADDR_SIZE is the size of addresses, in bytes.
-   OP_PTR is the start of the location expression.
-   OP_END is one past the last byte of the location expression.
+   EXPR is the location expression.
 
    This will throw an exception for various kinds of errors -- for
    example, if the expression cannot be compiled, or if the expression
    is invalid.  */
 
 static void
-dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc,
-			   unsigned int addr_size, const gdb_byte *op_ptr,
-			   const gdb_byte *op_end, dwarf2_per_cu *per_cu,
+dwarf2_compile_expr_to_ax (struct agent_expr *ax, struct axs_value *loc,
+			   unsigned int addr_size,
+			   gdb::array_view<const gdb_byte> expr,
+			   dwarf2_per_cu *per_cu,
 			   dwarf2_per_objfile *per_objfile)
 {
-  gdbarch *arch = expr->gdbarch;
+  gdbarch *arch = ax->gdbarch;
   std::vector<int> dw_labels, patches;
-  const gdb_byte * const base = op_ptr;
-  const gdb_byte *previous_piece = op_ptr;
+  const gdb_byte *previous_piece = expr.data ();
   enum bfd_endian byte_order = gdbarch_byte_order (arch);
   ULONGEST bits_collected = 0;
   unsigned int addr_size_bits = 8 * addr_size;
   bool bits_big_endian = byte_order == BFD_ENDIAN_BIG;
 
-  std::vector<int> offsets (op_end - op_ptr, -1);
+  std::vector<int> offsets (expr.size (), -1);
 
   /* By default we are making an address.  */
   loc->kind = axs_lvalue_memory;
 
+  const gdb_byte *const base = expr.data ();
+  const gdb_byte *op_ptr = expr.data ();
+  const gdb_byte *const op_end = expr.data () + expr.size ();
+
   while (op_ptr < op_end)
     {
       enum dwarf_location_atom op = (enum dwarf_location_atom) *op_ptr;
@@ -2429,7 +2407,7 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc,
       int64_t offset;
       int i;
 
-      offsets[op_ptr - base] = expr->buf.size ();
+      offsets[op_ptr - base] = ax->buf.size ();
       ++op_ptr;
 
       /* Our basic approach to code generation is to map DWARF
@@ -2482,7 +2460,7 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc,
 	case DW_OP_lit29:
 	case DW_OP_lit30:
 	case DW_OP_lit31:
-	  ax_const_l (expr, op - DW_OP_lit0);
+	  ax_const_l (ax, op - DW_OP_lit0);
 	  break;
 
 	case DW_OP_addr:
@@ -2494,57 +2472,57 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc,
 	     branching between the address and the TLS op.  */
 	  if (op_ptr >= op_end || *op_ptr != DW_OP_GNU_push_tls_address)
 	    uoffset += per_objfile->objfile->text_section_offset ();
-	  ax_const_l (expr, uoffset);
+	  ax_const_l (ax, uoffset);
 	  break;
 
 	case DW_OP_const1u:
-	  ax_const_l (expr, extract_unsigned_integer (op_ptr, 1, byte_order));
+	  ax_const_l (ax, extract_unsigned_integer (op_ptr, 1, byte_order));
 	  op_ptr += 1;
 	  break;
 
 	case DW_OP_const1s:
-	  ax_const_l (expr, extract_signed_integer (op_ptr, 1, byte_order));
+	  ax_const_l (ax, extract_signed_integer (op_ptr, 1, byte_order));
 	  op_ptr += 1;
 	  break;
 
 	case DW_OP_const2u:
-	  ax_const_l (expr, extract_unsigned_integer (op_ptr, 2, byte_order));
+	  ax_const_l (ax, extract_unsigned_integer (op_ptr, 2, byte_order));
 	  op_ptr += 2;
 	  break;
 
 	case DW_OP_const2s:
-	  ax_const_l (expr, extract_signed_integer (op_ptr, 2, byte_order));
+	  ax_const_l (ax, extract_signed_integer (op_ptr, 2, byte_order));
 	  op_ptr += 2;
 	  break;
 
 	case DW_OP_const4u:
-	  ax_const_l (expr, extract_unsigned_integer (op_ptr, 4, byte_order));
+	  ax_const_l (ax, extract_unsigned_integer (op_ptr, 4, byte_order));
 	  op_ptr += 4;
 	  break;
 
 	case DW_OP_const4s:
-	  ax_const_l (expr, extract_signed_integer (op_ptr, 4, byte_order));
+	  ax_const_l (ax, extract_signed_integer (op_ptr, 4, byte_order));
 	  op_ptr += 4;
 	  break;
 
 	case DW_OP_const8u:
-	  ax_const_l (expr, extract_unsigned_integer (op_ptr, 8, byte_order));
+	  ax_const_l (ax, extract_unsigned_integer (op_ptr, 8, byte_order));
 	  op_ptr += 8;
 	  break;
 
 	case DW_OP_const8s:
-	  ax_const_l (expr, extract_signed_integer (op_ptr, 8, byte_order));
+	  ax_const_l (ax, extract_signed_integer (op_ptr, 8, byte_order));
 	  op_ptr += 8;
 	  break;
 
 	case DW_OP_constu:
 	  op_ptr = safe_read_uleb128 (op_ptr, op_end, &uoffset);
-	  ax_const_l (expr, uoffset);
+	  ax_const_l (ax, uoffset);
 	  break;
 
 	case DW_OP_consts:
 	  op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
-	  ax_const_l (expr, offset);
+	  ax_const_l (ax, offset);
 	  break;
 
 	case DW_OP_reg0:
@@ -2602,7 +2580,7 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc,
 	      error (_("Cannot translate DW_OP_implicit_value of %d bytes"),
 		     (int) len);
 
-	    ax_const_l (expr, extract_unsigned_integer (op_ptr, len,
+	    ax_const_l (ax, extract_unsigned_integer (op_ptr, len,
 							byte_order));
 	    op_ptr += len;
 	    dwarf_expr_require_composition (op_ptr, op_end,
@@ -2651,11 +2629,11 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc,
 	case DW_OP_breg31:
 	  op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
 	  i = dwarf_reg_to_regnum_or_error (arch, op - DW_OP_breg0);
-	  ax_reg (expr, i);
+	  ax_reg (ax, i);
 	  if (offset != 0)
 	    {
-	      ax_const_l (expr, offset);
-	      ax_simple (expr, aop_add);
+	      ax_const_l (ax, offset);
+	      ax_simple (ax, aop_add);
 	    }
 	  break;
 
@@ -2664,23 +2642,21 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc,
 	    op_ptr = safe_read_uleb128 (op_ptr, op_end, &reg);
 	    op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
 	    i = dwarf_reg_to_regnum_or_error (arch, reg);
-	    ax_reg (expr, i);
+	    ax_reg (ax, i);
 	    if (offset != 0)
 	      {
-		ax_const_l (expr, offset);
-		ax_simple (expr, aop_add);
+		ax_const_l (ax, offset);
+		ax_simple (ax, aop_add);
 	      }
 	  }
 	  break;
 
 	case DW_OP_fbreg:
 	  {
-	    const gdb_byte *datastart;
-	    size_t datalen;
 	    const struct block *b;
 	    struct symbol *framefunc;
 
-	    b = block_for_pc (expr->scope);
+	    b = block_for_pc (ax->scope);
 
 	    if (!b)
 	      error (_("No block found for address"));
@@ -2690,20 +2666,19 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc,
 	    if (!framefunc)
 	      error (_("No function found for block"));
 
-	    func_get_frame_base_dwarf_block (framefunc, expr->scope,
-					     &datastart, &datalen);
+	    auto frame_base_expr = func_get_frame_base_dwarf_block (framefunc,
+								    ax->scope);
 
 	    op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
-	    dwarf2_compile_expr_to_ax (expr, loc, addr_size, datastart,
-				       datastart + datalen, per_cu,
-				       per_objfile);
+	    dwarf2_compile_expr_to_ax (ax, loc, addr_size, frame_base_expr,
+				       per_cu, per_objfile);
 	    if (loc->kind == axs_lvalue_register)
-	      require_rvalue (expr, loc);
+	      require_rvalue (ax, loc);
 
 	    if (offset != 0)
 	      {
-		ax_const_l (expr, offset);
-		ax_simple (expr, aop_add);
+		ax_const_l (ax, offset);
+		ax_simple (ax, aop_add);
 	      }
 
 	    loc->kind = axs_lvalue_memory;
@@ -2711,28 +2686,28 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc,
 	  break;
 
 	case DW_OP_dup:
-	  ax_simple (expr, aop_dup);
+	  ax_simple (ax, aop_dup);
 	  break;
 
 	case DW_OP_drop:
-	  ax_simple (expr, aop_pop);
+	  ax_simple (ax, aop_pop);
 	  break;
 
 	case DW_OP_pick:
 	  offset = *op_ptr++;
-	  ax_pick (expr, offset);
+	  ax_pick (ax, offset);
 	  break;
 
 	case DW_OP_swap:
-	  ax_simple (expr, aop_swap);
+	  ax_simple (ax, aop_swap);
 	  break;
 
 	case DW_OP_over:
-	  ax_pick (expr, 1);
+	  ax_pick (ax, 1);
 	  break;
 
 	case DW_OP_rot:
-	  ax_simple (expr, aop_rot);
+	  ax_simple (ax, aop_rot);
 	  break;
 
 	case DW_OP_deref:
@@ -2748,36 +2723,36 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc,
 	    if (size != 1 && size != 2 && size != 4 && size != 8)
 	      error (_("Unsupported size %d in %s"),
 		     size, get_DW_OP_name (op));
-	    access_memory (arch, expr, size * TARGET_CHAR_BIT);
+	    access_memory (arch, ax, size * TARGET_CHAR_BIT);
 	  }
 	  break;
 
 	case DW_OP_abs:
 	  /* Sign extend the operand.  */
-	  ax_ext (expr, addr_size_bits);
-	  ax_simple (expr, aop_dup);
-	  ax_const_l (expr, 0);
-	  ax_simple (expr, aop_less_signed);
-	  ax_simple (expr, aop_log_not);
-	  i = ax_goto (expr, aop_if_goto);
+	  ax_ext (ax, addr_size_bits);
+	  ax_simple (ax, aop_dup);
+	  ax_const_l (ax, 0);
+	  ax_simple (ax, aop_less_signed);
+	  ax_simple (ax, aop_log_not);
+	  i = ax_goto (ax, aop_if_goto);
 	  /* We have to emit 0 - X.  */
-	  ax_const_l (expr, 0);
-	  ax_simple (expr, aop_swap);
-	  ax_simple (expr, aop_sub);
-	  ax_label (expr, i, expr->buf.size ());
+	  ax_const_l (ax, 0);
+	  ax_simple (ax, aop_swap);
+	  ax_simple (ax, aop_sub);
+	  ax_label (ax, i, ax->buf.size ());
 	  break;
 
 	case DW_OP_neg:
 	  /* No need to sign extend here.  */
-	  ax_const_l (expr, 0);
-	  ax_simple (expr, aop_swap);
-	  ax_simple (expr, aop_sub);
+	  ax_const_l (ax, 0);
+	  ax_simple (ax, aop_swap);
+	  ax_simple (ax, aop_sub);
 	  break;
 
 	case DW_OP_not:
 	  /* Sign extend the operand.  */
-	  ax_ext (expr, addr_size_bits);
-	  ax_simple (expr, aop_bit_not);
+	  ax_ext (ax, addr_size_bits);
+	  ax_simple (ax, aop_bit_not);
 	  break;
 
 	case DW_OP_plus_uconst:
@@ -2786,116 +2761,116 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc,
 	     but we micro-optimize anyhow.  */
 	  if (reg != 0)
 	    {
-	      ax_const_l (expr, reg);
-	      ax_simple (expr, aop_add);
+	      ax_const_l (ax, reg);
+	      ax_simple (ax, aop_add);
 	    }
 	  break;
 
 	case DW_OP_and:
-	  ax_simple (expr, aop_bit_and);
+	  ax_simple (ax, aop_bit_and);
 	  break;
 
 	case DW_OP_div:
 	  /* Sign extend the operands.  */
-	  ax_ext (expr, addr_size_bits);
-	  ax_simple (expr, aop_swap);
-	  ax_ext (expr, addr_size_bits);
-	  ax_simple (expr, aop_swap);
-	  ax_simple (expr, aop_div_signed);
+	  ax_ext (ax, addr_size_bits);
+	  ax_simple (ax, aop_swap);
+	  ax_ext (ax, addr_size_bits);
+	  ax_simple (ax, aop_swap);
+	  ax_simple (ax, aop_div_signed);
 	  break;
 
 	case DW_OP_minus:
-	  ax_simple (expr, aop_sub);
+	  ax_simple (ax, aop_sub);
 	  break;
 
 	case DW_OP_mod:
-	  ax_simple (expr, aop_rem_unsigned);
+	  ax_simple (ax, aop_rem_unsigned);
 	  break;
 
 	case DW_OP_mul:
-	  ax_simple (expr, aop_mul);
+	  ax_simple (ax, aop_mul);
 	  break;
 
 	case DW_OP_or:
-	  ax_simple (expr, aop_bit_or);
+	  ax_simple (ax, aop_bit_or);
 	  break;
 
 	case DW_OP_plus:
-	  ax_simple (expr, aop_add);
+	  ax_simple (ax, aop_add);
 	  break;
 
 	case DW_OP_shl:
-	  ax_simple (expr, aop_lsh);
+	  ax_simple (ax, aop_lsh);
 	  break;
 
 	case DW_OP_shr:
-	  ax_simple (expr, aop_rsh_unsigned);
+	  ax_simple (ax, aop_rsh_unsigned);
 	  break;
 
 	case DW_OP_shra:
-	  ax_simple (expr, aop_rsh_signed);
+	  ax_simple (ax, aop_rsh_signed);
 	  break;
 
 	case DW_OP_xor:
-	  ax_simple (expr, aop_bit_xor);
+	  ax_simple (ax, aop_bit_xor);
 	  break;
 
 	case DW_OP_le:
 	  /* Sign extend the operands.  */
-	  ax_ext (expr, addr_size_bits);
-	  ax_simple (expr, aop_swap);
-	  ax_ext (expr, addr_size_bits);
+	  ax_ext (ax, addr_size_bits);
+	  ax_simple (ax, aop_swap);
+	  ax_ext (ax, addr_size_bits);
 	  /* Note no swap here: A <= B is !(B < A).  */
-	  ax_simple (expr, aop_less_signed);
-	  ax_simple (expr, aop_log_not);
+	  ax_simple (ax, aop_less_signed);
+	  ax_simple (ax, aop_log_not);
 	  break;
 
 	case DW_OP_ge:
 	  /* Sign extend the operands.  */
-	  ax_ext (expr, addr_size_bits);
-	  ax_simple (expr, aop_swap);
-	  ax_ext (expr, addr_size_bits);
-	  ax_simple (expr, aop_swap);
+	  ax_ext (ax, addr_size_bits);
+	  ax_simple (ax, aop_swap);
+	  ax_ext (ax, addr_size_bits);
+	  ax_simple (ax, aop_swap);
 	  /* A >= B is !(A < B).  */
-	  ax_simple (expr, aop_less_signed);
-	  ax_simple (expr, aop_log_not);
+	  ax_simple (ax, aop_less_signed);
+	  ax_simple (ax, aop_log_not);
 	  break;
 
 	case DW_OP_eq:
 	  /* Sign extend the operands.  */
-	  ax_ext (expr, addr_size_bits);
-	  ax_simple (expr, aop_swap);
-	  ax_ext (expr, addr_size_bits);
+	  ax_ext (ax, addr_size_bits);
+	  ax_simple (ax, aop_swap);
+	  ax_ext (ax, addr_size_bits);
 	  /* No need for a second swap here.  */
-	  ax_simple (expr, aop_equal);
+	  ax_simple (ax, aop_equal);
 	  break;
 
 	case DW_OP_lt:
 	  /* Sign extend the operands.  */
-	  ax_ext (expr, addr_size_bits);
-	  ax_simple (expr, aop_swap);
-	  ax_ext (expr, addr_size_bits);
-	  ax_simple (expr, aop_swap);
-	  ax_simple (expr, aop_less_signed);
+	  ax_ext (ax, addr_size_bits);
+	  ax_simple (ax, aop_swap);
+	  ax_ext (ax, addr_size_bits);
+	  ax_simple (ax, aop_swap);
+	  ax_simple (ax, aop_less_signed);
 	  break;
 
 	case DW_OP_gt:
 	  /* Sign extend the operands.  */
-	  ax_ext (expr, addr_size_bits);
-	  ax_simple (expr, aop_swap);
-	  ax_ext (expr, addr_size_bits);
+	  ax_ext (ax, addr_size_bits);
+	  ax_simple (ax, aop_swap);
+	  ax_ext (ax, addr_size_bits);
 	  /* Note no swap here: A > B is B < A.  */
-	  ax_simple (expr, aop_less_signed);
+	  ax_simple (ax, aop_less_signed);
 	  break;
 
 	case DW_OP_ne:
 	  /* Sign extend the operands.  */
-	  ax_ext (expr, addr_size_bits);
-	  ax_simple (expr, aop_swap);
-	  ax_ext (expr, addr_size_bits);
+	  ax_ext (ax, addr_size_bits);
+	  ax_simple (ax, aop_swap);
+	  ax_ext (ax, addr_size_bits);
 	  /* No need for a swap here.  */
-	  ax_simple (expr, aop_equal);
-	  ax_simple (expr, aop_log_not);
+	  ax_simple (ax, aop_equal);
+	  ax_simple (ax, aop_log_not);
 	  break;
 
 	case DW_OP_call_frame_cfa:
@@ -2903,26 +2878,25 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc,
 	    int regnum;
 	    CORE_ADDR text_offset;
 	    LONGEST off;
-	    const gdb_byte *cfa_start, *cfa_end;
+	    gdb::array_view<const gdb_byte> cfa_expr;
 
-	    if (dwarf2_fetch_cfa_info (arch, expr->scope, per_cu,
-				       &regnum, &off,
-				       &text_offset, &cfa_start, &cfa_end))
+	    if (dwarf2_fetch_cfa_info (arch, ax->scope, per_cu, &regnum,
+				       &off, &text_offset, cfa_expr))
 	      {
 		/* Register.  */
-		ax_reg (expr, regnum);
+		ax_reg (ax, regnum);
 		if (off != 0)
 		  {
-		    ax_const_l (expr, off);
-		    ax_simple (expr, aop_add);
+		    ax_const_l (ax, off);
+		    ax_simple (ax, aop_add);
 		  }
 	      }
 	    else
 	      {
 		/* Another expression.  */
-		ax_const_l (expr, text_offset);
-		dwarf2_compile_expr_to_ax (expr, loc, addr_size, cfa_start,
-					   cfa_end, per_cu, per_objfile);
+		ax_const_l (ax, text_offset);
+		dwarf2_compile_expr_to_ax (ax, loc, addr_size, cfa_expr,
+					   per_cu, per_objfile);
 	      }
 
 	    loc->kind = axs_lvalue_memory;
@@ -2941,7 +2915,7 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc,
 	case DW_OP_skip:
 	  offset = extract_signed_integer (op_ptr, 2, byte_order);
 	  op_ptr += 2;
-	  i = ax_goto (expr, aop_goto);
+	  i = ax_goto (ax, aop_goto);
 	  dw_labels.push_back (op_ptr + offset - base);
 	  patches.push_back (i);
 	  break;
@@ -2950,8 +2924,8 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc,
 	  offset = extract_signed_integer (op_ptr, 2, byte_order);
 	  op_ptr += 2;
 	  /* Zero extend the operand.  */
-	  ax_zero_ext (expr, addr_size_bits);
-	  i = ax_goto (expr, aop_if_goto);
+	  ax_zero_ext (ax, addr_size_bits);
+	  i = ax_goto (ax, aop_if_goto);
 	  dw_labels.push_back (op_ptr + offset - base);
 	  patches.push_back (i);
 	  break;
@@ -2984,18 +2958,18 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc,
 	    switch (loc->kind)
 	      {
 	      case axs_lvalue_register:
-		ax_reg (expr, loc->u.reg);
+		ax_reg (ax, loc->u.reg);
 		break;
 
 	      case axs_lvalue_memory:
 		/* Offset the pointer, if needed.  */
 		if (uoffset > 8)
 		  {
-		    ax_const_l (expr, uoffset / 8);
-		    ax_simple (expr, aop_add);
+		    ax_const_l (ax, uoffset / 8);
+		    ax_simple (ax, aop_add);
 		    uoffset %= 8;
 		  }
-		access_memory (arch, expr, size);
+		access_memory (arch, ax, size);
 		break;
 	      }
 
@@ -3008,18 +2982,18 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc,
 	      {
 		if (bits_big_endian)
 		  {
-		    ax_simple (expr, aop_swap);
-		    ax_const_l (expr, size);
-		    ax_simple (expr, aop_lsh);
+		    ax_simple (ax, aop_swap);
+		    ax_const_l (ax, size);
+		    ax_simple (ax, aop_lsh);
 		    /* We don't need a second swap here, because
 		       aop_bit_or is symmetric.  */
 		  }
 		else
 		  {
-		    ax_const_l (expr, size);
-		    ax_simple (expr, aop_lsh);
+		    ax_const_l (ax, size);
+		    ax_simple (ax, aop_lsh);
 		  }
-		ax_simple (expr, aop_bit_or);
+		ax_simple (ax, aop_bit_or);
 	      }
 
 	    bits_collected += size;
@@ -3039,9 +3013,9 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc,
 	    uoffset = extract_unsigned_integer (op_ptr, size, byte_order);
 	    op_ptr += size;
 
-	    auto get_frame_pc_from_expr = [expr] ()
+	    auto get_frame_pc_from_expr = [ax] ()
 	      {
-		return expr->scope;
+		return ax->scope;
 	      };
 	    cu_offset cuoffset = (cu_offset) uoffset;
 	    block = dwarf2_fetch_die_loc_cu_off (cuoffset, per_cu, per_objfile,
@@ -3050,9 +3024,8 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc,
 	    /* DW_OP_call_ref is currently not supported.  */
 	    gdb_assert (block.per_cu == per_cu);
 
-	    dwarf2_compile_expr_to_ax (expr, loc, addr_size, block.data,
-				       block.data + block.size, per_cu,
-				       per_objfile);
+	    dwarf2_compile_expr_to_ax (ax, loc, addr_size, block.expr (),
+				       per_cu, per_objfile);
 	  }
 	  break;
 
@@ -3073,7 +3046,7 @@ dwarf2_compile_expr_to_ax (struct agent_expr *expr, struct axs_value *loc,
       int targ = offsets[dw_labels[i]];
       if (targ == -1)
 	internal_error (_("invalid label"));
-      ax_label (expr, patches[i], targ);
+      ax_label (ax, patches[i], targ);
     }
 }
 
@@ -3087,9 +3060,8 @@ locexpr_read_variable (struct symbol *symbol, const frame_info_ptr &frame)
     = (struct dwarf2_locexpr_baton *) SYMBOL_LOCATION_BATON (symbol);
   struct value *val;
 
-  val = dwarf2_evaluate_loc_desc (symbol->type (), frame, dlbaton->data,
-				  dlbaton->size, dlbaton->per_cu,
-				  dlbaton->per_objfile);
+  val = dwarf2_evaluate_loc_desc (symbol->type (), frame, dlbaton->expr (),
+				  dlbaton->per_cu, dlbaton->per_objfile);
 
   return val;
 }
@@ -3104,8 +3076,7 @@ locexpr_read_variable_at_entry (struct symbol *symbol, const frame_info_ptr &fra
   struct dwarf2_locexpr_baton *dlbaton
     = (struct dwarf2_locexpr_baton *) SYMBOL_LOCATION_BATON (symbol);
 
-  return value_of_dwarf_block_entry (symbol->type (), frame, dlbaton->data,
-				     dlbaton->size);
+  return value_of_dwarf_block_entry (symbol->type (), frame, dlbaton->expr ());
 }
 
 /* Implementation of get_symbol_read_needs from
@@ -3118,10 +3089,8 @@ locexpr_get_symbol_read_needs (struct symbol *symbol)
     = (struct dwarf2_locexpr_baton *) SYMBOL_LOCATION_BATON (symbol);
 
   gdbarch *arch = dlbaton->per_objfile->objfile->arch ();
-  gdb::array_view<const gdb_byte> expr (dlbaton->data, dlbaton->size);
 
-  return dwarf2_get_symbol_read_needs (expr,
-				       dlbaton->per_cu,
+  return dwarf2_get_symbol_read_needs (dlbaton->expr (), dlbaton->per_cu,
 				       dlbaton->per_objfile,
 				       gdbarch_byte_order (arch),
 				       dlbaton->per_cu->addr_size (),
@@ -3196,8 +3165,7 @@ locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream,
       struct symbol *framefunc;
       int frame_reg = 0;
       int64_t frame_offset;
-      const gdb_byte *base_data, *new_data, *save_data = data;
-      size_t base_size;
+      const gdb_byte *new_data, *save_data = data;
       int64_t base_offset = 0;
 
       new_data = safe_read_sleb128 (data + 1, end, &frame_offset);
@@ -3217,24 +3185,27 @@ locexpr_describe_location_piece (struct symbol *symbol, struct ui_file *stream,
 	error (_("No function found for block for symbol \"%s\"."),
 	       symbol->print_name ());
 
-      func_get_frame_base_dwarf_block (framefunc, addr, &base_data, &base_size);
+      auto frame_base_expr = func_get_frame_base_dwarf_block (framefunc, addr);
+      gdb_byte op0 = frame_base_expr[0];
 
-      if (base_data[0] >= DW_OP_breg0 && base_data[0] <= DW_OP_breg31)
+      if (op0 >= DW_OP_breg0 && op0 <= DW_OP_breg31)
 	{
 	  const gdb_byte *buf_end;
 
-	  frame_reg = base_data[0] - DW_OP_breg0;
-	  buf_end = safe_read_sleb128 (base_data + 1, base_data + base_size,
+	  frame_reg = op0 - DW_OP_breg0;
+	  buf_end = safe_read_sleb128 (frame_base_expr.data () + 1,
+				       (frame_base_expr.data ()
+					+ frame_base_expr.size ()),
 				       &base_offset);
-	  if (buf_end != base_data + base_size)
+	  if (buf_end != frame_base_expr.data () + frame_base_expr.size ())
 	    error (_("Unexpected opcode after "
 		     "DW_OP_breg%u for symbol \"%s\"."),
 		   frame_reg, symbol->print_name ());
 	}
-      else if (base_data[0] >= DW_OP_reg0 && base_data[0] <= DW_OP_reg31)
+      else if (op0 >= DW_OP_reg0 && op0 <= DW_OP_reg31)
 	{
 	  /* The frame base is just the register, with no offset.  */
-	  frame_reg = base_data[0] - DW_OP_reg0;
+	  frame_reg = op0 - DW_OP_reg0;
 	  base_offset = 0;
 	}
       else
@@ -3751,12 +3722,13 @@ show_dwarf_always_disassemble (struct ui_file *file, int from_tty,
 static void
 locexpr_describe_location_1 (struct symbol *symbol, CORE_ADDR addr,
 			     struct ui_file *stream,
-			     const gdb_byte *data, size_t size,
+			     gdb::array_view<const gdb_byte> expr,
 			     unsigned int addr_size,
 			     int offset_size, dwarf2_per_cu *per_cu,
 			     dwarf2_per_objfile *per_objfile)
 {
-  const gdb_byte *end = data + size;
+  const gdb_byte *data = expr.data ();
+  const gdb_byte *const end = expr.data () + expr.size ();
   int first_piece = 1, bad = 0;
   objfile *objfile = per_objfile->objfile;
 
@@ -3854,7 +3826,7 @@ locexpr_describe_location (struct symbol *symbol, CORE_ADDR addr,
   int offset_size = dlbaton->per_cu->offset_size ();
 
   locexpr_describe_location_1 (symbol, addr, stream,
-			       dlbaton->data, dlbaton->size,
+			       dlbaton->expr (),
 			       addr_size, offset_size,
 			       dlbaton->per_cu, dlbaton->per_objfile);
 }
@@ -3873,9 +3845,8 @@ locexpr_tracepoint_var_ref (struct symbol *symbol, struct agent_expr *ax,
   if (dlbaton->size == 0)
     value->optimized_out = 1;
   else
-    dwarf2_compile_expr_to_ax (ax, value, addr_size, dlbaton->data,
-			       dlbaton->data + dlbaton->size, dlbaton->per_cu,
-			       dlbaton->per_objfile);
+    dwarf2_compile_expr_to_ax (ax, value, addr_size, dlbaton->expr (),
+			       dlbaton->per_cu, dlbaton->per_objfile);
 }
 
 /* symbol_computed_ops 'generate_c_location' method.  */
@@ -3890,14 +3861,14 @@ locexpr_generate_c_location (struct symbol *sym, string_file *stream,
   struct dwarf2_locexpr_baton *dlbaton
     = (struct dwarf2_locexpr_baton *) SYMBOL_LOCATION_BATON (sym);
   unsigned int addr_size = dlbaton->per_cu->addr_size ();
+  auto expr = dlbaton->expr ();
 
-  if (dlbaton->size == 0)
+  if (expr.empty ())
     error (_("symbol \"%s\" is optimized out"), sym->natural_name ());
 
-  compile_dwarf_expr_to_c (stream, result_name,
-			   sym, pc, gdbarch, registers_used, addr_size,
-			   dlbaton->data, dlbaton->data + dlbaton->size,
-			   dlbaton->per_cu, dlbaton->per_objfile);
+  compile_dwarf_expr_to_c (stream, result_name, sym, pc, gdbarch,
+			   registers_used, addr_size, expr, dlbaton->per_cu,
+			   dlbaton->per_objfile);
 #else
   gdb_assert_not_reached ("Compile support was disabled");
 #endif
@@ -3926,16 +3897,11 @@ loclist_read_variable (struct symbol *symbol, const frame_info_ptr &frame)
 {
   struct dwarf2_loclist_baton *dlbaton
     = (struct dwarf2_loclist_baton *) SYMBOL_LOCATION_BATON (symbol);
-  struct value *val;
-  const gdb_byte *data;
-  size_t size;
   CORE_ADDR pc = frame ? get_frame_address_in_block (frame) : 0;
+  auto expr = dwarf2_find_location_expression (dlbaton, pc);
 
-  data = dwarf2_find_location_expression (dlbaton, &size, pc);
-  val = dwarf2_evaluate_loc_desc (symbol->type (), frame, data, size,
-				  dlbaton->per_cu, dlbaton->per_objfile);
-
-  return val;
+  return dwarf2_evaluate_loc_desc (symbol->type (), frame, expr,
+				   dlbaton->per_cu, dlbaton->per_objfile);
 }
 
 /* Read variable SYMBOL like loclist_read_variable at (callee) FRAME's function
@@ -3951,18 +3917,16 @@ loclist_read_variable_at_entry (struct symbol *symbol, const frame_info_ptr &fra
 {
   struct dwarf2_loclist_baton *dlbaton
     = (struct dwarf2_loclist_baton *) SYMBOL_LOCATION_BATON (symbol);
-  const gdb_byte *data;
-  size_t size;
   CORE_ADDR pc;
 
   if (frame == NULL || !get_frame_func_if_available (frame, &pc))
     return value::allocate_optimized_out (symbol->type ());
 
-  data = dwarf2_find_location_expression (dlbaton, &size, pc, true);
-  if (data == NULL)
+  auto expr = dwarf2_find_location_expression (dlbaton, pc, true);
+  if (expr.empty ())
     return value::allocate_optimized_out (symbol->type ());
 
-  return value_of_dwarf_block_entry (symbol->type (), frame, data, size);
+  return value_of_dwarf_block_entry (symbol->type (), frame, expr);
 }
 
 /* Implementation of get_symbol_read_needs from
@@ -4088,9 +4052,10 @@ loclist_describe_location (struct symbol *symbol, CORE_ADDR addr,
 		  paddress (gdbarch, high_reloc));
 
       /* Now describe this particular location.  */
-      locexpr_describe_location_1 (symbol, low_reloc, stream, loc_ptr, length,
-				   addr_size, offset_size,
-				   dlbaton->per_cu, per_objfile);
+      locexpr_describe_location_1 (symbol, low_reloc, stream,
+				   gdb::make_array_view (loc_ptr, length),
+				   addr_size, offset_size, dlbaton->per_cu,
+				   per_objfile);
 
       gdb_printf (stream, "\n");
 
@@ -4106,16 +4071,14 @@ loclist_tracepoint_var_ref (struct symbol *symbol, struct agent_expr *ax,
 {
   struct dwarf2_loclist_baton *dlbaton
     = (struct dwarf2_loclist_baton *) SYMBOL_LOCATION_BATON (symbol);
-  const gdb_byte *data;
-  size_t size;
   unsigned int addr_size = dlbaton->per_cu->addr_size ();
 
-  data = dwarf2_find_location_expression (dlbaton, &size, ax->scope);
-  if (size == 0)
+  auto expr = dwarf2_find_location_expression (dlbaton, ax->scope);
+  if (expr.empty ())
     value->optimized_out = 1;
   else
-    dwarf2_compile_expr_to_ax (ax, value, addr_size, data, data + size,
-			       dlbaton->per_cu, dlbaton->per_objfile);
+    dwarf2_compile_expr_to_ax (ax, value, addr_size, expr, dlbaton->per_cu,
+			       dlbaton->per_objfile);
 }
 
 /* symbol_computed_ops 'generate_c_location' method.  */
@@ -4130,17 +4093,13 @@ loclist_generate_c_location (struct symbol *sym, string_file *stream,
   struct dwarf2_loclist_baton *dlbaton
     = (struct dwarf2_loclist_baton *) SYMBOL_LOCATION_BATON (sym);
   unsigned int addr_size = dlbaton->per_cu->addr_size ();
-  const gdb_byte *data;
-  size_t size;
+  auto expr = dwarf2_find_location_expression (dlbaton, pc);
 
-  data = dwarf2_find_location_expression (dlbaton, &size, pc);
-  if (size == 0)
+  if (expr.empty ())
     error (_("symbol \"%s\" is optimized out"), sym->natural_name ());
 
-  compile_dwarf_expr_to_c (stream, result_name,
-			   sym, pc, gdbarch, registers_used, addr_size,
-			   data, data + size,
-			   dlbaton->per_cu,
+  compile_dwarf_expr_to_c (stream, result_name, sym, pc, gdbarch,
+			   registers_used, addr_size, expr, dlbaton->per_cu,
 			   dlbaton->per_objfile);
 #else
   gdb_assert_not_reached ("Compile support was disabled");
diff --git a/gdb/dwarf2/loc.h b/gdb/dwarf2/loc.h
index d175ba67941..192e53318d6 100644
--- a/gdb/dwarf2/loc.h
+++ b/gdb/dwarf2/loc.h
@@ -21,6 +21,7 @@
 #define GDB_DWARF2_LOC_H
 
 #include "gdbtypes.h"
+#include "dwarf2/attribute.h"
 #include "dwarf2/expr.h"
 
 struct symbol_computed_ops;
@@ -37,23 +38,16 @@ struct axs_value;
 extern unsigned int entry_values_debug;
 
 /* Find a particular location expression from a location list.  */
-const gdb_byte *dwarf2_find_location_expression
-  (const dwarf2_loclist_baton *baton,
-   size_t *locexpr_length,
-   CORE_ADDR pc,
-   bool at_entry = false);
-
-/* Find the frame base information for FRAMEFUNC at PC.  START is an
-   out parameter which is set to point to the DWARF expression to
-   compute.  LENGTH is an out parameter which is set to the length of
-   the DWARF expression.  This throws an exception on error or if an
-   expression is not found; the returned length will never be
-   zero.  */
-
-extern void func_get_frame_base_dwarf_block (struct symbol *framefunc,
-					     CORE_ADDR pc,
-					     const gdb_byte **start,
-					     size_t *length);
+gdb::array_view<const gdb_byte> dwarf2_find_location_expression
+  (const dwarf2_loclist_baton *baton, CORE_ADDR pc, bool at_entry = false);
+
+/* Find the frame base information for FRAMEFUNC at PC and return the
+   DWARF expression to compute.
+
+   Throw an exception if no expression is found.  */
+
+gdb::array_view<const gdb_byte> func_get_frame_base_dwarf_block
+  (struct symbol *framefunc, CORE_ADDR pc);
 
 /* A helper function to find the definition of NAME and compute its
    value.  Returns nullptr if the name is not found.  */
@@ -72,13 +66,13 @@ call_site_parameter *dwarf_expr_reg_to_entry_parameter
    dwarf2_per_objfile **per_objfile_return);
 
 
-/* Evaluate a location description, starting at DATA and with length
-   SIZE, to find the current location of variable of TYPE in the context
-   of FRAME.  AS_LVAL defines if the resulting struct value is expected to
-   be a value or a location description.  */
+/* Evaluate the location description LOC_DESC to find the current location
+   of variable of TYPE in the context of FRAME.  AS_LVAL defines if the
+   resulting struct value is expected to be a value or a location
+   description.  */
 
 value *dwarf2_evaluate_loc_desc (type *type, const frame_info_ptr &frame,
-				 const gdb_byte *data, size_t size,
+				 gdb::array_view<const gdb_byte> loc_desc,
 				 dwarf2_per_cu *per_cu,
 				 dwarf2_per_objfile *per_objfile,
 				 bool as_lval = true);
@@ -132,8 +126,26 @@ void dwarf2_compile_property_to_c (string_file *stream,
 
 struct dwarf2_locexpr_baton
 {
-  /* Pointer to the start of the location expression.  Valid only if SIZE is
-     not zero.  */
+  /* Return the expression in this baton.  */
+  gdb::array_view<const gdb_byte> expr () const
+  { return gdb::make_array_view (data, size); }
+
+  /* Set the expression in this baton from EXPR.  */
+  void set_expr (gdb::array_view<const gdb_byte> expr)
+  {
+    data = expr.data ();
+    size = expr.size ();
+  }
+
+  /* Set the expression in this baton from BLOCK.  */
+  void set_expr (const dwarf_block &block)
+  {
+    data = block.data;
+    size = block.size;
+  }
+
+  /* Pointer to the start of the location expression.  nullptr for optimized
+     out expressions.  */
   const gdb_byte *data;
 
   /* Length of the location expression.  For optimized out expressions it is
@@ -176,6 +188,10 @@ struct dwarf2_field_location_baton : public dwarf2_locexpr_baton
 
 struct dwarf2_loclist_baton
 {
+  /* Return the location list in this baton.  */
+  gdb::array_view<const gdb_byte> expr () const
+  { return gdb::make_array_view (data, size); }
+
   /* The initial base address for the location list, based on the compilation
      unit.  */
   unrelocated_addr base_address;
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 58646cff54b..a1081da2317 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -5269,8 +5269,7 @@ dwarf2_compute_name (const char *name,
 
 		      if (baton != NULL)
 			v = dwarf2_evaluate_loc_desc (type, NULL,
-						      baton->data,
-						      baton->size,
+						      baton->expr (),
 						      baton->per_cu,
 						      baton->per_objfile);
 		      else if (bytes != NULL)
@@ -8102,13 +8101,10 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
     /* Keep NULL DWARF_BLOCK.  */;
   else if (attr->form_is_block ())
     {
-      struct dwarf2_locexpr_baton *dlbaton;
-      struct dwarf_block *block = attr->as_block ();
+      dwarf2_locexpr_baton *dlbaton
+	= OBSTACK_ZALLOC (&objfile->objfile_obstack, dwarf2_locexpr_baton);
 
-      dlbaton = OBSTACK_ZALLOC (&objfile->objfile_obstack,
-				struct dwarf2_locexpr_baton);
-      dlbaton->data = block->data;
-      dlbaton->size = block->size;
+      dlbaton->set_expr (*attr->as_block ());
       dlbaton->per_objfile = per_objfile;
       dlbaton->per_cu = cu->per_cu;
 
@@ -8228,14 +8224,12 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
 	}
       else
 	{
-	  struct dwarf_block *block = loc->as_block ();
+	  auto block = loc->as_block ()->view ();
 
-	  parameter->u.dwarf_reg = dwarf_block_to_dwarf_reg
-	    (block->data, &block->data[block->size]);
+	  parameter->u.dwarf_reg = dwarf_block_to_dwarf_reg (block);
 	  if (parameter->u.dwarf_reg != -1)
 	    parameter->kind = CALL_SITE_PARAMETER_DWARF_REG;
-	  else if (dwarf_block_to_sp_offset (gdbarch, block->data,
-					     &block->data[block->size],
+	  else if (dwarf_block_to_sp_offset (gdbarch, block,
 					     &parameter->u.fb_offset))
 	    parameter->kind = CALL_SITE_PARAMETER_FB_OFFSET;
 	  else
@@ -9389,8 +9383,9 @@ handle_member_location (struct die_info *die, struct dwarf2_cu *cu,
 	      else
 		dlbaton = OBSTACK_ZALLOC (&objfile->objfile_obstack,
 					  struct dwarf2_locexpr_baton);
-	      dlbaton->data = data_member_location_attr->as_block ()->data;
-	      dlbaton->size = data_member_location_attr->as_block ()->size;
+
+	      dlbaton->set_expr (*data_member_location_attr->as_block ());
+
 	      /* When using this baton, we want to compute the address
 		 of the field, not the value.  This is why
 		 is_reference is set to false here.  */
@@ -9423,8 +9418,8 @@ handle_member_location (struct die_info *die, struct dwarf2_cu *cu,
 	      dwarf2_locexpr_baton *dlbaton
 		= OBSTACK_ZALLOC (&per_objfile->objfile->objfile_obstack,
 				  dwarf2_locexpr_baton);
-	      dlbaton->data = data_bit_offset_attr->as_block ()->data;
-	      dlbaton->size = data_bit_offset_attr->as_block ()->size;
+
+	      dlbaton->set_expr (*data_bit_offset_attr->as_block ());
 	      dlbaton->per_objfile = per_objfile;
 	      dlbaton->per_cu = cu->per_cu;
 
@@ -11755,7 +11750,6 @@ mark_common_block_symbol_computed (struct symbol *sym,
   dwarf2_per_objfile *per_objfile = cu->per_objfile;
   struct objfile *objfile = per_objfile->objfile;
   struct dwarf2_locexpr_baton *baton;
-  gdb_byte *ptr;
   unsigned int cu_off;
   enum bfd_endian byte_order = gdbarch_byte_order (objfile->arch ());
   LONGEST offset = 0;
@@ -11771,18 +11765,19 @@ mark_common_block_symbol_computed (struct symbol *sym,
   baton->per_cu = cu->per_cu;
   gdb_assert (baton->per_cu);
 
-  baton->size = 5 /* DW_OP_call4 */ + 1 /* DW_OP_plus */;
+  std::size_t size = 5 /* DW_OP_call4 */ + 1 /* DW_OP_plus */;
 
   if (member_loc->form_is_constant ())
     {
       offset = member_loc->unsigned_constant ().value_or (0);
-      baton->size += 1 /* DW_OP_addr */ + cu->header.addr_size;
+      size += 1 /* DW_OP_addr */ + cu->header.addr_size;
     }
   else
-    baton->size += member_loc->as_block ()->size;
+    size += member_loc->as_block ()->size;
 
-  ptr = (gdb_byte *) obstack_alloc (&objfile->objfile_obstack, baton->size);
-  baton->data = ptr;
+  gdb_byte *const start
+    = (gdb_byte *) obstack_alloc (&objfile->objfile_obstack, size);
+  gdb_byte *ptr = start;
 
   *ptr++ = DW_OP_call4;
   cu_off = common_die->sect_off - cu->per_cu->sect_off ();
@@ -11805,7 +11800,9 @@ mark_common_block_symbol_computed (struct symbol *sym,
     }
 
   *ptr++ = DW_OP_plus;
-  gdb_assert (ptr - baton->data == baton->size);
+  gdb_assert (ptr - start == size);
+
+  baton->set_expr (gdb::make_array_view (start, size));
 
   SYMBOL_LOCATION_BATON (sym) = baton;
   sym->set_loc_class_index (dwarf2_locexpr_index);
@@ -12787,13 +12784,10 @@ get_mpz_for_rational (dwarf2_cu *cu, gdb_mpz *value, attribute *attr)
       *value = gdb_mpz (1);
     }
   else if (attr->form_is_block ())
-    {
-      dwarf_block *blk = attr->as_block ();
-      value->read (gdb::make_array_view (blk->data, blk->size),
-		   bfd_big_endian (cu->per_objfile->objfile->obfd.get ())
-		   ? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE,
-		   true);
-    }
+    value->read (attr->as_block ()->view (),
+		 (bfd_big_endian (cu->per_objfile->objfile->obfd.get ())
+		  ? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE),
+		 true);
   else
     {
       /* Rational constants for Ada are always unsigned.  */
@@ -13441,8 +13435,7 @@ attr_to_dynamic_prop (const struct attribute *attr, struct die_info *die,
       else
 	block = *attr->as_block ();
 
-      baton->locexpr.size = block.size;
-      baton->locexpr.data = block.data;
+      baton->locexpr.set_expr (block);
       switch (attr->name)
 	{
 	case DW_AT_string_length:
@@ -13498,9 +13491,7 @@ attr_to_dynamic_prop (const struct attribute *attr, struct die_info *die,
 		baton->property_type = die_type (target_die, target_cu);
 		baton->locexpr.per_cu = cu->per_cu;
 		baton->locexpr.per_objfile = per_objfile;
-		struct dwarf_block *block = target_attr->as_block ();
-		baton->locexpr.size = block->size;
-		baton->locexpr.data = block->data;
+		baton->locexpr.set_expr (*target_attr->as_block ());
 		baton->locexpr.is_reference = true;
 		prop->set_locexpr (baton);
 		gdb_assert (prop->baton () != NULL);
@@ -16015,9 +16006,9 @@ dwarf2_const_value_attr (const struct attribute *attr, struct type *type,
 	(*baton)->per_cu = cu->per_cu;
 	gdb_assert ((*baton)->per_cu);
 
-	(*baton)->size = 2 + cu_header->addr_size;
-	data = (gdb_byte *) obstack_alloc (obstack, (*baton)->size);
-	(*baton)->data = data;
+	std::size_t size = 2 + cu_header->addr_size;
+	data = (gdb_byte *) obstack_alloc (obstack, size);
+	(*baton)->set_expr (gdb::make_array_view (data, size));
 
 	data[0] = DW_OP_addr;
 	store_unsigned_integer (&data[1], cu_header->addr_size,
@@ -17080,23 +17071,17 @@ dwarf2_fetch_die_loc_sect_off (sect_offset sect_off, dwarf2_per_cu *per_cu,
 
   if (!attr)
     {
-      /* DWARF: "If there is no such attribute, then there is no effect.".
-	 DATA is ignored if SIZE is 0.  */
-
-      retval.data = NULL;
-      retval.size = 0;
+      /* DWARF: "If there is no such attribute, then there is no effect.".  */
+      retval.set_expr (gdb::array_view<const gdb_byte> ());
     }
   else if (attr->form_is_section_offset ())
     {
       struct dwarf2_loclist_baton loclist_baton;
       CORE_ADDR pc = get_frame_pc ();
-      size_t size;
 
       fill_in_loclist_baton (cu, &loclist_baton, attr);
 
-      retval.data = dwarf2_find_location_expression (&loclist_baton,
-						     &size, pc);
-      retval.size = size;
+      retval.set_expr (dwarf2_find_location_expression (&loclist_baton, pc));
     }
   else
     {
@@ -17106,9 +17091,7 @@ dwarf2_fetch_die_loc_sect_off (sect_offset sect_off, dwarf2_per_cu *per_cu,
 		 " [in module %s]"),
 	       sect_offset_str (sect_off), objfile_name (objfile));
 
-      struct dwarf_block *block = attr->as_block ();
-      retval.data = block->data;
-      retval.size = block->size;
+      retval.set_expr (*attr->as_block ());
     }
   retval.per_objfile = per_objfile;
   retval.per_cu = cu->per_cu;
@@ -17932,9 +17915,7 @@ dwarf2_symbol_mark_computed (const struct attribute *attr, struct symbol *sym,
 	     info_buffer for SYM's objfile; right now we never release
 	     that buffer, but when we do clean up properly this may
 	     need to change.  */
-	  struct dwarf_block *block = attr->as_block ();
-	  baton->size = block->size;
-	  baton->data = block->data;
+	  baton->set_expr (*attr->as_block ());
 	}
       else
 	{
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 7b1a8238613..5a3db47d84f 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -1154,12 +1154,11 @@ struct symbol_computed_ops
 
 struct symbol_block_ops
 {
-  /* Fill in *START and *LENGTH with DWARF block data of function
-     FRAMEFUNC valid for inferior context address PC.  Set *LENGTH to
-     zero if such location is not valid for PC; *START is left
-     uninitialized in such case.  */
-  void (*find_frame_base_location) (struct symbol *framefunc, CORE_ADDR pc,
-				    const gdb_byte **start, size_t *length);
+  /* Return the DWARF block data of function FRAMEFUNC valid for inferior
+     context address PC.  Return an empty view if no such location is
+     valid for PC.  */
+  gdb::array_view<const gdb_byte> (*find_frame_base_location)
+    (struct symbol *framefunc, CORE_ADDR pc);
 
   /* Return the frame base address.  FRAME is the frame for which we want to
      compute the base address while FRAMEFUNC is the symbol for the
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.