Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH] gdb/dwarf2: pass around DWARF expressions as gdb::array_view
@ 2026-04-29  0:55 simon.marchi
  2026-05-01 16:35 ` Tom Tromey
  0 siblings, 1 reply; 3+ messages in thread
From: simon.marchi @ 2026-04-29  0:55 UTC (permalink / raw)
  To: gdb-patches; +Cc: Simon Marchi

From: Simon Marchi <simon.marchi@efficios.com>

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
---
 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 dae3e2ebd6b0..9f189ef1cc79 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 ca222d2e961a..15fc22cb62cc 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 653638ee1cc8..776ce43825d4 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 872f48cb662a..e55197213907 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 222f563e2a95..38b77f317413 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 eaa166935342..02b0e41f6fde 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 @@ struct dwarf_expr_context
   /* 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 @@ struct dwarf_expr_context
   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 70895e90696d..5b9f41cd53a4 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);
-\f
-
-/* 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 6ecd5d0d6563..d3c71c3d16e4 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 a493a46dcfc9..5bf863e13d53 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 d175ba679412..192e53318d67 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 1288c076aba1..cb20dcab6f41 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.  */
@@ -13444,8 +13438,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:
@@ -13501,9 +13494,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);
@@ -16018,9 +16009,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,
@@ -17078,23 +17069,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
     {
@@ -17104,9 +17089,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;
@@ -17930,9 +17913,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 7b1a82386131..5a3db47d84fd 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

base-commit: 237eed6d652aa1b341c913d37142d060eb9481c4
-- 
2.54.0


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] gdb/dwarf2: pass around DWARF expressions as gdb::array_view
  2026-04-29  0:55 [PATCH] gdb/dwarf2: pass around DWARF expressions as gdb::array_view simon.marchi
@ 2026-05-01 16:35 ` Tom Tromey
  2026-05-02  4:14   ` Simon Marchi
  0 siblings, 1 reply; 3+ messages in thread
From: Tom Tromey @ 2026-05-01 16:35 UTC (permalink / raw)
  To: simon.marchi; +Cc: gdb-patches, Simon Marchi

>>>>> "Simon" == simon marchi <simon.marchi@polymtl.ca> writes:

Simon> This patch converts a bunch of functions to take or return DWARF
Simon> expressions as `gdb::array_view<const gdb_byte>`, instead of raw pointer
Simon> and size.  It doesn't do any non-trivial change to function
Simon> implementations, but the idea is that we could change them (for example
Simon> dwarf_expr_context::execute_stack_op) to operate on the array view
Simon> directly, giving us bounds checking when building in debug mode.  But
Simon> that is not as trivial.

I skimmed this and it seems fine to me.
Approved-By: Tom Tromey <tom@tromey.com>

Simon> This patch also doesn't change structure fields to array_views (for
Simon> instance, dwarf2_loclist_baton), because that would make them
Simon> non-trivially constructible, and we'd (technically) need to change how
Simon> they are allocated.

I thought this sounded backward but I suppose it refers to the fact that
these are stored in a union inside dwarf2_property_baton.

A fix for that might be to use a class hierarchy rather than a union.

thanks,
Tom

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] gdb/dwarf2: pass around DWARF expressions as gdb::array_view
  2026-05-01 16:35 ` Tom Tromey
@ 2026-05-02  4:14   ` Simon Marchi
  0 siblings, 0 replies; 3+ messages in thread
From: Simon Marchi @ 2026-05-02  4:14 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches, Simon Marchi



On 2026-05-01 12:35, Tom Tromey wrote:
>>>>>> "Simon" == simon marchi <simon.marchi@polymtl.ca> writes:
> 
> Simon> This patch converts a bunch of functions to take or return DWARF
> Simon> expressions as `gdb::array_view<const gdb_byte>`, instead of raw pointer
> Simon> and size.  It doesn't do any non-trivial change to function
> Simon> implementations, but the idea is that we could change them (for example
> Simon> dwarf_expr_context::execute_stack_op) to operate on the array view
> Simon> directly, giving us bounds checking when building in debug mode.  But
> Simon> that is not as trivial.
> 
> I skimmed this and it seems fine to me.
> Approved-By: Tom Tromey <tom@tromey.com>

Thanks, pushed.

> Simon> This patch also doesn't change structure fields to array_views (for
> Simon> instance, dwarf2_loclist_baton), because that would make them
> Simon> non-trivially constructible, and we'd (technically) need to change how
> Simon> they are allocated.
> 
> I thought this sounded backward but I suppose it refers to the fact that
> these are stored in a union inside dwarf2_property_baton.
> 
> A fix for that might be to use a class hierarchy rather than a union.

Yes, I meant that we would start to have to call "new" on them.  They
are currently allocated with XOBNEW, which is disallows on
non-trivially-constructible types.  I guess that's what
allocate_on_obstack is for?  Anyway, I had to stop somewhere with this
patch otherwise the scope creeps too far.

Simon

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-05-02  4:15 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-04-29  0:55 [PATCH] gdb/dwarf2: pass around DWARF expressions as gdb::array_view simon.marchi
2026-05-01 16:35 ` Tom Tromey
2026-05-02  4:14   ` Simon Marchi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox