gdb/dwarf: C++ify batons

Message ID 20260506221808.57296-1-simon.marchi@efficios.com
State New
Headers
Series gdb/dwarf: C++ify batons |

Commit Message

Simon Marchi May 6, 2026, 10:18 p.m. UTC
  From: Simon Marchi <simon.marchi@polymtl.ca>

Change the various DWARF baton types to have constructors and to hold
array views, instead of raw pointer + size.  Keep them allocated on
obstacks (via allocate_on_obstack), so that they don't need to be
tracked and deleted individually.

Split dwarf2_property_baton into three distinct classes:

 - dwarf2_locexpr_property_baton
 - dwarf2_loclist_property_baton
 - dwarf2_field_property_baton

I made it such that the constructors of dwarf2_locexpr_property_baton
and dwarf2_loclist_property_baton take a dwarf2_locexpr_baton or
dwarf2_loclist_baton, which is copied into the internal field.  This is
perhaps not as efficient as possible (a bit more copying than needed),
but it's straightforward, but they are small objects.  For reference, a
dwarf2_locexpr_baton is 40 bytes and dwarf2_loclist_baton is 48 bytes.

dwarf2_field_location_baton inherits from dwarf2_locexpr_baton, and they
both inherit from allocate_on_obstack.  This requires having those
`using` statements in dwarf2_field_location_baton, since there are
competing operators new and delete coming from the two base classes.
Not super pretty, but it works.

Change-Id: I5e71f50d5266f93d8fd33366923384f6c1d7eac2
---
 gdb/dwarf2/expr.c |   2 +-
 gdb/dwarf2/loc.c  |  80 +++++++--------
 gdb/dwarf2/loc.h  | 134 +++++++++++++++----------
 gdb/dwarf2/read.c | 242 ++++++++++++++++++----------------------------
 gdb/gdbtypes.c    |  16 ++-
 gdb/gdbtypes.h    |  45 ++++++---
 gdb/gnu-v3-abi.c  |   6 +-
 7 files changed, 259 insertions(+), 266 deletions(-)


base-commit: 9e6e0c3cd9e6d5ee4953f72a805cff5f150aa2fd
  

Patch

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index 38b77f317413..8a6f23974092 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -846,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.expr ());
+  this->eval (block.expr);
 }
 
 /* See expr.h.  */
diff --git a/gdb/dwarf2/loc.c b/gdb/dwarf2/loc.c
index 5bf863e13d53..afc175c54fa9 100644
--- a/gdb/dwarf2/loc.c
+++ b/gdb/dwarf2/loc.c
@@ -376,10 +376,8 @@  dwarf2_find_location_expression (const dwarf2_loclist_baton *baton,
   CORE_ADDR text_offset = baton->per_objfile->objfile->text_section_offset ();
   unrelocated_addr unrel_pc = (unrelocated_addr) (pc - text_offset);
   unrelocated_addr base_address = baton->base_address;
-  const gdb_byte *loc_ptr, *buf_end;
-
-  loc_ptr = baton->data;
-  buf_end = baton->data + baton->size;
+  const gdb_byte *loc_ptr = baton->loclist.data ();
+  const gdb_byte *buf_end = loc_ptr + baton->loclist.size ();
 
   while (1)
     {
@@ -487,7 +485,7 @@  locexpr_find_frame_base_location (struct symbol *framefunc, CORE_ADDR pc)
   struct dwarf2_locexpr_baton *symbaton
     = (struct dwarf2_locexpr_baton *) SYMBOL_LOCATION_BATON (framefunc);
 
-  return symbaton->expr ();
+  return symbaton->expr;
 }
 
 /* Implement the struct symbol_block_ops::get_frame_base method for
@@ -678,8 +676,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->expr (),
-					dwarf_block->per_cu,
+					dwarf_block->expr, dwarf_block->per_cu,
 					dwarf_block->per_objfile);
 	/* DW_AT_call_target is a DWARF expression, not a DWARF location.  */
 	if (val->lval () == lval_memory)
@@ -1462,10 +1459,9 @@  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.  */
-  auto expr = baton.expr ();
-  if (!expr.empty ())
-    return dwarf2_evaluate_loc_desc_full (orig_type, frame, expr, baton.per_cu,
-					  baton.per_objfile,
+  if (!baton.expr.empty ())
+    return dwarf2_evaluate_loc_desc_full (orig_type, frame, baton.expr,
+					  baton.per_cu, baton.per_objfile,
 					  type->target_type (), byte_offset);
   else
     return fetch_const_value_from_synthetic_pointer (die, byte_offset, per_cu,
@@ -1572,7 +1568,7 @@  dwarf2_locexpr_baton_eval (const struct dwarf2_locexpr_baton *dlbaton,
 			   gdb::array_view<CORE_ADDR> push_values,
 			   bool *is_reference)
 {
-  if (dlbaton->size == 0)
+  if (dlbaton->expr.empty ())
     return false;
 
   dwarf2_per_objfile *per_objfile = dlbaton->per_objfile;
@@ -1588,8 +1584,7 @@  dwarf2_locexpr_baton_eval (const struct dwarf2_locexpr_baton *dlbaton,
 
   try
     {
-      result = ctx.evaluate (dlbaton->expr (), true, per_cu, frame,
-			     addr_stack);
+      result = ctx.evaluate (dlbaton->expr, true, per_cu, frame, addr_stack);
     }
   catch (const gdb_exception_error &ex)
     {
@@ -1645,7 +1640,7 @@  dwarf2_evaluate_property (const dynamic_prop *prop,
     {
     case PROP_LOCEXPR:
       {
-	const struct dwarf2_property_baton *baton = prop->baton ();
+	const dwarf2_locexpr_property_baton *baton = prop->locexpr ();
 	gdb_assert (baton->property_type != NULL);
 
 	bool is_reference = baton->locexpr.is_reference;
@@ -1687,7 +1682,7 @@  dwarf2_evaluate_property (const dynamic_prop *prop,
 
     case PROP_LOCLIST:
       {
-	const dwarf2_property_baton *baton = prop->baton ();
+	const dwarf2_loclist_property_baton *baton = prop->loclist ();
 	CORE_ADDR pc;
 	struct value *val;
 
@@ -1716,7 +1711,7 @@  dwarf2_evaluate_property (const dynamic_prop *prop,
 
     case PROP_FIELD:
       {
-	const dwarf2_property_baton *baton = prop->baton ();
+	const dwarf2_field_property_baton *baton = prop->field ();
 	const struct property_addr_info *pinfo;
 
 	for (pinfo = addr_stack; pinfo != NULL; pinfo = pinfo->next)
@@ -1791,14 +1786,15 @@  dwarf2_compile_property_to_c (string_file *stream,
 			      struct symbol *sym)
 {
 #if defined (HAVE_COMPILE)
-  const dwarf2_property_baton *baton = prop->baton ();
   gdb::array_view<const gdb_byte> expr;
   dwarf2_per_cu *per_cu;
   dwarf2_per_objfile *per_objfile;
 
   if (prop->kind () == PROP_LOCEXPR)
     {
-      expr = baton->locexpr.expr ();
+      const dwarf2_locexpr_property_baton *baton = prop->locexpr ();
+
+      expr = baton->locexpr.expr;
       per_cu = baton->locexpr.per_cu;
       per_objfile = baton->locexpr.per_objfile;
     }
@@ -1806,6 +1802,8 @@  dwarf2_compile_property_to_c (string_file *stream,
     {
       gdb_assert (prop->kind () == PROP_LOCLIST);
 
+      const dwarf2_loclist_property_baton *baton = prop->loclist ();
+
       expr = dwarf2_find_location_expression (&baton->loclist, pc);
       per_cu = baton->loclist.per_cu;
       per_objfile = baton->loclist.per_objfile;
@@ -2166,7 +2164,7 @@  dwarf2_get_symbol_read_needs (gdb::array_view<const gdb_byte> expr,
 	      {
 		gdbarch *arch = baton.per_objfile->objfile->arch ();
 		symbol_needs
-		  = dwarf2_get_symbol_read_needs (baton.expr (),
+		  = dwarf2_get_symbol_read_needs (baton.expr,
 						  baton.per_cu,
 						  baton.per_objfile,
 						  gdbarch_byte_order (arch),
@@ -2217,7 +2215,7 @@  dwarf2_get_symbol_read_needs (gdb::array_view<const gdb_byte> expr,
 	      {
 		gdbarch *arch = baton.per_objfile->objfile->arch ();
 		symbol_needs
-		  = dwarf2_get_symbol_read_needs (baton.expr (),
+		  = dwarf2_get_symbol_read_needs (baton.expr,
 						  baton.per_cu,
 						  baton.per_objfile,
 						  gdbarch_byte_order (arch),
@@ -3007,7 +3005,6 @@  dwarf2_compile_expr_to_ax (struct agent_expr *ax, struct axs_value *loc,
 	case DW_OP_call2:
 	case DW_OP_call4:
 	  {
-	    struct dwarf2_locexpr_baton block;
 	    int size = (op == DW_OP_call2 ? 2 : 4);
 
 	    uoffset = extract_unsigned_integer (op_ptr, size, byte_order);
@@ -3018,14 +3015,15 @@  dwarf2_compile_expr_to_ax (struct agent_expr *ax, struct axs_value *loc,
 		return ax->scope;
 	      };
 	    cu_offset cuoffset = (cu_offset) uoffset;
-	    block = dwarf2_fetch_die_loc_cu_off (cuoffset, per_cu, per_objfile,
-						 get_frame_pc_from_expr);
+	    dwarf2_locexpr_baton block
+	      = dwarf2_fetch_die_loc_cu_off (cuoffset, per_cu, per_objfile,
+					     get_frame_pc_from_expr);
 
 	    /* DW_OP_call_ref is currently not supported.  */
 	    gdb_assert (block.per_cu == per_cu);
 
-	    dwarf2_compile_expr_to_ax (ax, loc, addr_size, block.expr (),
-				       per_cu, per_objfile);
+	    dwarf2_compile_expr_to_ax (ax, loc, addr_size, block.expr, per_cu,
+				       per_objfile);
 	  }
 	  break;
 
@@ -3058,12 +3056,9 @@  locexpr_read_variable (struct symbol *symbol, const frame_info_ptr &frame)
 {
   struct dwarf2_locexpr_baton *dlbaton
     = (struct dwarf2_locexpr_baton *) SYMBOL_LOCATION_BATON (symbol);
-  struct value *val;
 
-  val = dwarf2_evaluate_loc_desc (symbol->type (), frame, dlbaton->expr (),
-				  dlbaton->per_cu, dlbaton->per_objfile);
-
-  return val;
+  return dwarf2_evaluate_loc_desc (symbol->type (), frame, dlbaton->expr,
+				   dlbaton->per_cu, dlbaton->per_objfile);
 }
 
 /* Return the value of SYMBOL in FRAME at (callee) FRAME's function
@@ -3076,7 +3071,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->expr ());
+  return value_of_dwarf_block_entry (symbol->type (), frame, dlbaton->expr);
 }
 
 /* Implementation of get_symbol_read_needs from
@@ -3090,7 +3085,7 @@  locexpr_get_symbol_read_needs (struct symbol *symbol)
 
   gdbarch *arch = dlbaton->per_objfile->objfile->arch ();
 
-  return dwarf2_get_symbol_read_needs (dlbaton->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 (),
@@ -3825,10 +3820,9 @@  locexpr_describe_location (struct symbol *symbol, CORE_ADDR addr,
   unsigned int addr_size = dlbaton->per_cu->addr_size ();
   int offset_size = dlbaton->per_cu->offset_size ();
 
-  locexpr_describe_location_1 (symbol, addr, stream,
-			       dlbaton->expr (),
-			       addr_size, offset_size,
-			       dlbaton->per_cu, dlbaton->per_objfile);
+  locexpr_describe_location_1 (symbol, addr, stream, dlbaton->expr, addr_size,
+			       offset_size, dlbaton->per_cu,
+			       dlbaton->per_objfile);
 }
 
 /* Describe the location of SYMBOL as an agent value in VALUE, generating
@@ -3842,10 +3836,10 @@  locexpr_tracepoint_var_ref (struct symbol *symbol, struct agent_expr *ax,
     = (struct dwarf2_locexpr_baton *) SYMBOL_LOCATION_BATON (symbol);
   unsigned int addr_size = dlbaton->per_cu->addr_size ();
 
-  if (dlbaton->size == 0)
+  if (dlbaton->expr.empty ())
     value->optimized_out = 1;
   else
-    dwarf2_compile_expr_to_ax (ax, value, addr_size, dlbaton->expr (),
+    dwarf2_compile_expr_to_ax (ax, value, addr_size, dlbaton->expr,
 			       dlbaton->per_cu, dlbaton->per_objfile);
 }
 
@@ -3861,7 +3855,7 @@  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 ();
+  auto expr = dlbaton->expr;
 
   if (expr.empty ())
     error (_("symbol \"%s\" is optimized out"), sym->natural_name ());
@@ -3954,7 +3948,6 @@  loclist_describe_location (struct symbol *symbol, CORE_ADDR addr,
 {
   struct dwarf2_loclist_baton *dlbaton
     = (struct dwarf2_loclist_baton *) SYMBOL_LOCATION_BATON (symbol);
-  const gdb_byte *loc_ptr, *buf_end;
   dwarf2_per_objfile *per_objfile = dlbaton->per_objfile;
   struct objfile *objfile = per_objfile->objfile;
   struct gdbarch *gdbarch = objfile->arch ();
@@ -3964,9 +3957,8 @@  loclist_describe_location (struct symbol *symbol, CORE_ADDR addr,
   int signed_addr_p = bfd_get_sign_extend_vma (objfile->obfd.get ());
   unrelocated_addr base_address = dlbaton->base_address;
   int done = 0;
-
-  loc_ptr = dlbaton->data;
-  buf_end = dlbaton->data + dlbaton->size;
+  const gdb_byte *loc_ptr = dlbaton->loclist.data ();
+  const gdb_byte *buf_end = loc_ptr + dlbaton->loclist.size ();
 
   gdb_printf (stream, _("multi-location:\n"));
 
diff --git a/gdb/dwarf2/loc.h b/gdb/dwarf2/loc.h
index 192e53318d67..4a04bdccc600 100644
--- a/gdb/dwarf2/loc.h
+++ b/gdb/dwarf2/loc.h
@@ -124,42 +124,27 @@  void dwarf2_compile_property_to_c (string_file *stream,
    expression; "struct dwarf2_loclist_baton" is for a symbol with a
    location list.  */
 
-struct dwarf2_locexpr_baton
+struct dwarf2_locexpr_baton : allocate_on_obstack<dwarf2_locexpr_baton>
 {
-  /* 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)
+  dwarf2_locexpr_baton (gdb::array_view<const gdb_byte> expr,
+			dwarf2_per_objfile &per_objfile, dwarf2_per_cu &per_cu)
+    : expr (expr),
+      per_objfile (&per_objfile),
+      per_cu (&per_cu)
   {
-    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
-     zero.  */
-  size_t size;
+  /* The location expression.  Empty for optimized out expressions.  */
+  gdb::array_view<const gdb_byte> expr;
 
   /* When true this location expression is a reference and actually
      describes the address at which the value of the attribute can be
      found.  When false the expression provides the value of the attribute
      directly.  */
-  bool is_reference;
+  bool is_reference = false;
 
   /* True if this object is actually a dwarf2_field_location_baton.  */
-  bool is_field_location;
+  bool is_field_location = false;
 
   /* The objfile that was used when creating this.  */
   dwarf2_per_objfile *per_objfile;
@@ -176,31 +161,48 @@  struct dwarf2_locexpr_baton
    'is_field_location' member in dwarf2_locexpr_baton.  See also
    apply_bit_offset_to_field.  */
 
-struct dwarf2_field_location_baton : public dwarf2_locexpr_baton
+struct dwarf2_field_location_baton
+  : dwarf2_locexpr_baton,
+    allocate_on_obstack<dwarf2_field_location_baton>
 {
+  using allocate_on_obstack<dwarf2_field_location_baton>::operator new;
+  using allocate_on_obstack<dwarf2_field_location_baton>::operator delete;
+
+  dwarf2_field_location_baton (gdb::array_view<const gdb_byte> expr,
+			       dwarf2_per_objfile &per_objfile,
+			       dwarf2_per_cu &per_cu, LONGEST bit_offset,
+			       LONGEST explicit_byte_size)
+    : dwarf2_locexpr_baton (expr, per_objfile, per_cu),
+      bit_offset (bit_offset),
+      explicit_byte_size (explicit_byte_size)
+  {
+    is_field_location = true;
+  }
+
   /* The bit offset, coming from DW_AT_bit_offset.  */
-  LONGEST bit_offset;
+  LONGEST bit_offset = 0;
 
   /* The DW_AT_byte_size of the field.  If no explicit byte size was
      specified, this is 0.  */
-  LONGEST explicit_byte_size;
+  LONGEST explicit_byte_size = 0;
 };
 
-struct dwarf2_loclist_baton
+struct dwarf2_loclist_baton : allocate_on_obstack<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); }
+  dwarf2_loclist_baton (gdb::array_view<const gdb_byte> loclist,
+			dwarf2_per_objfile &per_objfile, dwarf2_per_cu &per_cu)
+    : loclist (loclist),
+      per_objfile (&per_objfile),
+      per_cu (&per_cu)
+  {
+  }
 
   /* The initial base address for the location list, based on the compilation
      unit.  */
-  unrelocated_addr base_address;
+  unrelocated_addr base_address {};
 
-  /* Pointer to the start of the location list.  */
-  const gdb_byte *data;
-
-  /* Length of the location list.  */
-  size_t size;
+  /* The location list.  */
+  gdb::array_view<const gdb_byte> loclist;
 
   /* The objfile that was used when creating this.  */
   dwarf2_per_objfile *per_objfile;
@@ -211,10 +213,10 @@  struct dwarf2_loclist_baton
 
   /* Non-zero if the location list lives in .debug_loc.dwo.
      The format of entries in this section are different.  */
-  unsigned char from_dwo;
+  unsigned char from_dwo = 0;
 
   /* The version of DWARF this loclist comes from.  */
-  unsigned char dwarf_version;
+  unsigned char dwarf_version = 0;
 };
 
 /* A dynamic property is either expressed as a single location expression
@@ -225,23 +227,57 @@  struct dwarf2_loclist_baton
 
 struct dwarf2_property_baton
 {
+  dwarf2_property_baton (type &property_type)
+    : property_type (&property_type)
+  {
+  }
+
   /* If the property is an indirection, we need to evaluate the location
      in the context of the type PROPERTY_TYPE.  If the property is supplied
      by value then it will be of PROPERTY_TYPE.  This field should never be
      NULL.  */
   struct type *property_type;
-  union
+};
+
+struct dwarf2_locexpr_property_baton
+  : dwarf2_property_baton,
+    allocate_on_obstack<dwarf2_locexpr_property_baton>
+{
+  dwarf2_locexpr_property_baton (type &property_type,
+				 const dwarf2_locexpr_baton &locexpr)
+    : dwarf2_property_baton (property_type),
+      locexpr (locexpr)
   {
-    /* Location expression either evaluated in the context of
-       PROPERTY_TYPE, or a value of type PROPERTY_TYPE.  */
-    struct dwarf2_locexpr_baton locexpr;
+  }
 
-    /* Location list to be evaluated in the context of PROPERTY_TYPE.  */
-    struct dwarf2_loclist_baton loclist;
+  /* Location expression either evaluated in the context of
+     PROPERTY_TYPE, or a value of type PROPERTY_TYPE.  */
+  dwarf2_locexpr_baton locexpr;
+};
 
-    /* The location is stored in a field of PROPERTY_TYPE.  */
-    struct field field;
-  };
+struct dwarf2_loclist_property_baton
+  : dwarf2_property_baton,
+    allocate_on_obstack<dwarf2_loclist_property_baton>
+{
+  dwarf2_loclist_property_baton (type &property_type,
+				 const dwarf2_loclist_baton &loclist)
+    : dwarf2_property_baton (property_type),
+      loclist (loclist)
+  {
+  }
+
+  /* Location list to be evaluated in the context of PROPERTY_TYPE.  */
+  dwarf2_loclist_baton loclist;
+};
+
+struct dwarf2_field_property_baton
+  : dwarf2_property_baton,
+    allocate_on_obstack<dwarf2_field_property_baton>
+{
+  using dwarf2_property_baton::dwarf2_property_baton;
+
+  /* The field of PROPERTY_TYPE that contains the property value.  */
+  struct field field {};
 };
 
 extern const struct symbol_computed_ops dwarf2_locexpr_funcs;
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index efe96f6510da..f28c26090b39 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -907,9 +907,8 @@  static struct dwarf_block *dwarf_alloc_block (struct dwarf2_cu *);
 
 static void dwarf_decode_macros (struct dwarf2_cu *, unsigned int, int);
 
-static void fill_in_loclist_baton (struct dwarf2_cu *cu,
-				   struct dwarf2_loclist_baton *baton,
-				   const struct attribute *attr);
+static dwarf2_loclist_baton make_loclist_baton (struct dwarf2_cu *cu,
+						const struct attribute *attr);
 
 static void dwarf2_symbol_mark_computed (const struct attribute *attr,
 					 struct symbol *sym,
@@ -5268,8 +5267,7 @@  dwarf2_compute_name (const char *name,
 		      struct value_print_options opts;
 
 		      if (baton != NULL)
-			v = dwarf2_evaluate_loc_desc (type, NULL,
-						      baton->expr (),
+			v = dwarf2_evaluate_loc_desc (type, NULL, baton->expr,
 						      baton->per_cu,
 						      baton->per_objfile);
 		      else if (bytes != NULL)
@@ -8101,12 +8099,9 @@  read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
     /* Keep NULL DWARF_BLOCK.  */;
   else if (attr->form_is_block ())
     {
-      dwarf2_locexpr_baton *dlbaton
-	= OBSTACK_ZALLOC (&objfile->objfile_obstack, dwarf2_locexpr_baton);
-
-      dlbaton->set_expr (*attr->as_block ());
-      dlbaton->per_objfile = per_objfile;
-      dlbaton->per_cu = cu->per_cu;
+      auto dlbaton = new (&objfile->objfile_obstack)
+	dwarf2_locexpr_baton (attr->as_block ()->view (), *per_objfile,
+			      *cu->per_cu);
 
       call_site->target.set_loc_dwarf_block (dlbaton);
     }
@@ -9370,28 +9365,21 @@  handle_member_location (struct die_info *die, struct dwarf2_cu *cu,
 	      dwarf2_per_objfile *per_objfile = cu->per_objfile;
 	      struct objfile *objfile = per_objfile->objfile;
 	      struct dwarf2_locexpr_baton *dlbaton;
-	      if (has_bit_offset)
-		{
-		  dwarf2_field_location_baton *flbaton
-		    = OBSTACK_ZALLOC (&objfile->objfile_obstack,
-				      dwarf2_field_location_baton);
-		  flbaton->is_field_location = true;
-		  flbaton->bit_offset = bit_offset;
-		  flbaton->explicit_byte_size = anonymous_size;
-		  dlbaton = flbaton;
-		}
-	      else
-		dlbaton = OBSTACK_ZALLOC (&objfile->objfile_obstack,
-					  struct dwarf2_locexpr_baton);
+	      gdb::array_view<const gdb_byte> expr
+		= data_member_location_attr->as_block ()->view ();
 
-	      dlbaton->set_expr (*data_member_location_attr->as_block ());
+	      if (has_bit_offset)
+		dlbaton = new (&objfile->objfile_obstack)
+		  dwarf2_field_location_baton (expr, *per_objfile, *cu->per_cu,
+					       bit_offset, anonymous_size);
+	      else
+		dlbaton = new (&objfile->objfile_obstack)
+		  dwarf2_locexpr_baton (expr, *per_objfile, *cu->per_cu);
 
 	      /* 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.  */
 	      dlbaton->is_reference = false;
-	      dlbaton->per_objfile = per_objfile;
-	      dlbaton->per_cu = cu->per_cu;
 
 	      field->set_loc_dwarf_block_addr (dlbaton);
 	    }
@@ -9415,13 +9403,9 @@  handle_member_location (struct die_info *die, struct dwarf2_cu *cu,
 	      /* This is a DWARF extension.  See
 		 https://dwarfstd.org/issues/250501.1.html.  */
 	      dwarf2_per_objfile *per_objfile = cu->per_objfile;
-	      dwarf2_locexpr_baton *dlbaton
-		= OBSTACK_ZALLOC (&per_objfile->objfile->objfile_obstack,
-				  dwarf2_locexpr_baton);
-
-	      dlbaton->set_expr (*data_bit_offset_attr->as_block ());
-	      dlbaton->per_objfile = per_objfile;
-	      dlbaton->per_cu = cu->per_cu;
+	      auto dlbaton = new (&per_objfile->objfile->objfile_obstack)
+		dwarf2_locexpr_baton ((data_bit_offset_attr->as_block ()
+				       ->view ()), *per_objfile, *cu->per_cu);
 
 	      field->set_loc_dwarf_block_bitpos (dlbaton);
 	    }
@@ -10738,21 +10722,6 @@  handle_struct_member_die (struct die_info *child_die, struct type *type,
     handle_variant (child_die, type, fi, template_args, cu);
 }
 
-/* Create a property baton for a field.  DIE is the field's DIE.  The
-   baton's "field" member is filled in, but the other members of the
-   baton are not.  The new property baton is returned.  */
-
-static dwarf2_property_baton *
-find_field_create_baton (dwarf2_cu *cu, die_info *die)
-{
-  dwarf2_property_baton *result
-    = XOBNEW (&cu->per_objfile->objfile->objfile_obstack,
-	      struct dwarf2_property_baton);
-  memset (&result->field, 0, sizeof (result->field));
-  compute_field_location (cu, die, &result->field);
-  return result;
-}
-
 /* Finish creating a structure or union type, including filling in its
    members and creating a symbol for it. This function also handles Fortran
    namelist variables, their items or members and creating a symbol for
@@ -11749,7 +11718,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;
   unsigned int cu_off;
   enum bfd_endian byte_order = gdbarch_byte_order (objfile->arch ());
   LONGEST offset = 0;
@@ -11759,12 +11727,6 @@  mark_common_block_symbol_computed (struct symbol *sym,
   gdb_assert (member_loc->form_is_block ()
 	      || member_loc->form_is_constant ());
 
-  baton = OBSTACK_ZALLOC (&objfile->objfile_obstack,
-			  struct dwarf2_locexpr_baton);
-  baton->per_objfile = per_objfile;
-  baton->per_cu = cu->per_cu;
-  gdb_assert (baton->per_cu);
-
   std::size_t size = 5 /* DW_OP_call4 */ + 1 /* DW_OP_plus */;
 
   if (member_loc->form_is_constant ())
@@ -11802,7 +11764,9 @@  mark_common_block_symbol_computed (struct symbol *sym,
   *ptr++ = DW_OP_plus;
   gdb_assert (ptr - start == size);
 
-  baton->set_expr (gdb::make_array_view (start, size));
+  auto baton = new (&objfile->objfile_obstack)
+    dwarf2_locexpr_baton (gdb::make_array_view (start, size), *per_objfile,
+			  *cu->per_cu);
 
   SYMBOL_LOCATION_BATON (sym) = baton;
   sym->set_loc_class_index (dwarf2_locexpr_index);
@@ -13403,7 +13367,6 @@  attr_to_dynamic_prop (const struct attribute *attr, struct die_info *die,
 		      struct dwarf2_cu *cu, struct dynamic_prop *prop,
 		      struct type *default_type)
 {
-  struct dwarf2_property_baton *baton;
   dwarf2_per_objfile *per_objfile = cu->per_objfile;
   struct objfile *objfile = per_objfile->objfile;
   struct obstack *obstack = &objfile->objfile_obstack;
@@ -13415,27 +13378,26 @@  attr_to_dynamic_prop (const struct attribute *attr, struct die_info *die,
 
   if (attr->form_is_block ())
     {
-      baton = XOBNEW (obstack, struct dwarf2_property_baton);
-      baton->property_type = default_type;
-      baton->locexpr.per_cu = cu->per_cu;
-      baton->locexpr.per_objfile = per_objfile;
+      gdb::array_view<const gdb_byte> expr;
 
-      struct dwarf_block block;
       if (attr->form == DW_FORM_data16)
 	{
-	  size_t data_size = 16;
-	  block.size = (data_size
-			+ 2 /* Extra bytes for DW_OP and arg.  */);
-	  gdb_byte *data = XOBNEWVEC (obstack, gdb_byte, block.size);
-	  data[0] = DW_OP_implicit_value;
-	  data[1] = data_size;
-	  memcpy (&data[2], attr->as_block ()->data, data_size);
-	  block.data = data;
+	  std::size_t data_size = 16;
+	  std::size_t expr_size = (data_size
+				   + 2 /* Extra bytes for DW_OP and arg.  */);
+	  gdb_byte *expr_data = XOBNEWVEC (obstack, gdb_byte, expr_size);
+	  expr_data[0] = DW_OP_implicit_value;
+	  expr_data[1] = data_size;
+	  memcpy (&expr_data[2], attr->as_block ()->data, data_size);
+	  expr = gdb::make_array_view (expr_data, expr_size);
 	}
       else
-	block = *attr->as_block ();
+	expr = attr->as_block ()->view ();
+
+      auto baton = new (obstack)
+	dwarf2_locexpr_property_baton (*default_type,
+				       {expr, *per_objfile, *cu->per_cu});
 
-      baton->locexpr.set_expr (block);
       switch (attr->name)
 	{
 	case DW_AT_string_length:
@@ -13447,7 +13409,6 @@  attr_to_dynamic_prop (const struct attribute *attr, struct die_info *die,
 	}
 
       prop->set_locexpr (baton);
-      gdb_assert (prop->baton () != NULL);
     }
   else if (attr->form_is_ref ())
     {
@@ -13479,22 +13440,21 @@  attr_to_dynamic_prop (const struct attribute *attr, struct die_info *die,
 	  case DW_AT_location:
 	    if (target_attr->form_is_section_offset ())
 	      {
-		baton = XOBNEW (obstack, struct dwarf2_property_baton);
-		baton->property_type = die_type (target_die, target_cu);
-		fill_in_loclist_baton (cu, &baton->loclist, target_attr);
+		type *property_type = die_type (target_die, target_cu);
+		auto baton = new (obstack) dwarf2_loclist_property_baton
+		  (*property_type, make_loclist_baton (cu, target_attr));
 		prop->set_loclist (baton);
-		gdb_assert (prop->baton () != NULL);
 	      }
 	    else if (target_attr->form_is_block ())
 	      {
-		baton = XOBNEW (obstack, struct dwarf2_property_baton);
-		baton->property_type = die_type (target_die, target_cu);
-		baton->locexpr.per_cu = cu->per_cu;
-		baton->locexpr.per_objfile = per_objfile;
-		baton->locexpr.set_expr (*target_attr->as_block ());
+		type *property_type = die_type (target_die, target_cu);
+		auto baton = new (obstack)
+		  dwarf2_locexpr_property_baton (*property_type,
+						 {(target_attr->as_block ()
+						   ->view()), *per_objfile,
+						  *cu->per_cu});
 		baton->locexpr.is_reference = true;
 		prop->set_locexpr (baton);
-		gdb_assert (prop->baton () != NULL);
 	      }
 	    else
 	      {
@@ -13506,12 +13466,12 @@  attr_to_dynamic_prop (const struct attribute *attr, struct die_info *die,
 	  case DW_AT_data_member_location:
 	  case DW_AT_data_bit_offset:
 	    {
-	      baton = find_field_create_baton (cu, target_die);
-	      if (baton == nullptr)
-		return false;
+	      type *property_type = read_type_die (target_die->parent,
+						   target_cu);
+	      auto baton = new (&cu->per_objfile->objfile->objfile_obstack)
+		dwarf2_field_property_baton (*property_type);
 
-	      baton->property_type = read_type_die (target_die->parent,
-						    target_cu);
+	      compute_field_location (cu, target_die, &baton->field);
 	      prop->set_field (baton);
 	      break;
 	    }
@@ -13524,12 +13484,13 @@  attr_to_dynamic_prop (const struct attribute *attr, struct die_info *die,
       switch (attr->name)
 	{
 	case DW_AT_string_length:
-	  baton = XOBNEW (obstack, struct dwarf2_property_baton);
-	  baton->property_type = default_type;
-	  fill_in_loclist_baton (cu, &baton->loclist, attr);
-	  prop->set_loclist (baton);
-	  gdb_assert (prop->baton () != NULL);
-	  break;
+	  {
+	    auto baton = new (obstack)
+	      dwarf2_loclist_property_baton (*default_type,
+					     make_loclist_baton (cu, attr));
+	    prop->set_loclist (baton);
+	    break;
+	  }
 	default:
 	  goto invalid;
 	}
@@ -16002,8 +15963,6 @@  dwarf2_const_value_attr (const struct attribute *attr, struct type *type,
     case DW_FORM_addrx:
     case DW_FORM_GNU_addr_index:
       {
-	gdb_byte *data;
-
 	if (type->length () != cu_header->addr_size)
 	  dwarf2_const_value_length_mismatch_complaint (name,
 							cu_header->addr_size,
@@ -16011,14 +15970,11 @@  dwarf2_const_value_attr (const struct attribute *attr, struct type *type,
 	/* Symbols of this form are reasonably rare, so we just
 	   piggyback on the existing location code rather than writing
 	   a new implementation of symbol_computed_ops.  */
-	*baton = OBSTACK_ZALLOC (obstack, struct dwarf2_locexpr_baton);
-	(*baton)->per_objfile = per_objfile;
-	(*baton)->per_cu = cu->per_cu;
-	gdb_assert ((*baton)->per_cu);
-
 	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));
+	auto data = (gdb_byte *) obstack_alloc (obstack, size);
+	*baton = new (obstack)
+	  dwarf2_locexpr_baton (gdb::make_array_view (data, size),
+				*per_objfile, *cu->per_cu);
 
 	data[0] = DW_OP_addr;
 	store_unsigned_integer (&data[1], cu_header->addr_size,
@@ -17029,7 +16985,6 @@  dwarf2_fetch_die_loc_sect_off (sect_offset sect_off, dwarf2_per_cu *per_cu,
 			       bool resolve_abstract_p)
 {
   struct attribute *attr;
-  struct dwarf2_locexpr_baton retval;
   struct objfile *objfile = per_objfile->objfile;
 
   dwarf2_cu *cu = per_objfile->get_cu (per_cu);
@@ -17079,19 +17034,18 @@  dwarf2_fetch_die_loc_sect_off (sect_offset sect_off, dwarf2_per_cu *per_cu,
 	}
     }
 
+  gdb::array_view<const gdb_byte> expr;
+
   if (!attr)
     {
       /* 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;
+      dwarf2_loclist_baton loclist_baton = make_loclist_baton (cu, attr);
       CORE_ADDR pc = get_frame_pc ();
 
-      fill_in_loclist_baton (cu, &loclist_baton, attr);
-
-      retval.set_expr (dwarf2_find_location_expression (&loclist_baton, pc));
+      expr = dwarf2_find_location_expression (&loclist_baton, pc);
     }
   else
     {
@@ -17101,10 +17055,10 @@  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));
 
-      retval.set_expr (*attr->as_block ());
+      expr = attr->as_block ()->view ();
     }
-  retval.per_objfile = per_objfile;
-  retval.per_cu = cu->per_cu;
+
+  dwarf2_locexpr_baton retval (expr, *per_objfile, *cu->per_cu);
 
   per_objfile->age_comp_units ();
 
@@ -17854,29 +17808,30 @@  cu_debug_rnglists_section (struct dwarf2_cu *cu, dwarf_tag tag)
 
 /* A helper function that fills in a dwarf2_loclist_baton.  */
 
-static void
-fill_in_loclist_baton (struct dwarf2_cu *cu,
-		       struct dwarf2_loclist_baton *baton,
-		       const struct attribute *attr)
+static dwarf2_loclist_baton
+make_loclist_baton (struct dwarf2_cu *cu, const struct attribute *attr)
 {
   dwarf2_per_objfile *per_objfile = cu->per_objfile;
   struct dwarf2_section_info *section = cu_debug_loc_section (cu);
 
   section->read (per_objfile->objfile);
 
-  baton->per_objfile = per_objfile;
-  baton->per_cu = cu->per_cu;
-  gdb_assert (baton->per_cu);
   /* We don't know how long the location list is, but make sure we
      don't run off the edge of the section.  */
-  baton->size = section->size - attr->as_unsigned ();
-  baton->data = section->buffer + attr->as_unsigned ();
+  std::size_t loclist_size = section->size - attr->as_unsigned ();
+  const gdb_byte *loclist_data = section->buffer + attr->as_unsigned ();
+
+  dwarf2_loclist_baton baton (gdb::make_array_view (loclist_data,
+						    loclist_size),
+			      *per_objfile, *cu->per_cu);
+
   if (cu->base_address.has_value ())
-    baton->base_address = *cu->base_address;
-  else
-    baton->base_address = {};
-  baton->from_dwo = cu->dwo_unit != NULL;
-  baton->dwarf_version = cu->header.version;
+    baton.base_address = *cu->base_address;
+
+  baton.from_dwo = cu->dwo_unit != NULL;
+  baton.dwarf_version = cu->header.version;
+
+  return baton;
 }
 
 static void
@@ -17893,11 +17848,8 @@  dwarf2_symbol_mark_computed (const struct attribute *attr, struct symbol *sym,
 	 other branch.  */
       && attr->as_unsigned () < section->size)
     {
-      struct dwarf2_loclist_baton *baton;
-
-      baton = XOBNEW (&objfile->objfile_obstack, struct dwarf2_loclist_baton);
-
-      fill_in_loclist_baton (cu, baton, attr);
+      auto baton = new (&objfile->objfile_obstack)
+	dwarf2_loclist_baton (make_loclist_baton (cu, attr));
 
       if (!cu->base_address.has_value ())
 	complaint (_("Location list used without "
@@ -17910,13 +17862,7 @@  dwarf2_symbol_mark_computed (const struct attribute *attr, struct symbol *sym,
     }
   else
     {
-      struct dwarf2_locexpr_baton *baton;
-
-      baton = OBSTACK_ZALLOC (&objfile->objfile_obstack,
-			      struct dwarf2_locexpr_baton);
-      baton->per_objfile = per_objfile;
-      baton->per_cu = cu->per_cu;
-      gdb_assert (baton->per_cu);
+      gdb::array_view<const gdb_byte> expr;
 
       if (attr->form_is_block ())
 	{
@@ -17925,18 +17871,18 @@  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.  */
-	  baton->set_expr (*attr->as_block ());
+	  expr = attr->as_block ()->view ();
 	}
       else
-	{
-	  dwarf2_invalid_attrib_class_complaint ("location description",
-						 sym->natural_name ());
-	  baton->size = 0;
-	}
+	dwarf2_invalid_attrib_class_complaint ("location description",
+					       sym->natural_name ());
 
-      sym->set_loc_class_index ((is_block
-			      ? dwarf2_locexpr_block_index
-			      : dwarf2_locexpr_index));
+      auto baton = new (&objfile->objfile_obstack)
+	dwarf2_locexpr_baton (expr, *per_objfile, *cu->per_cu);
+
+      sym->set_loc_class_index (is_block
+				? dwarf2_locexpr_block_index
+				: dwarf2_locexpr_index);
       SYMBOL_LOCATION_BATON (sym) = baton;
     }
 }
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 2f566583509e..2d577b09359e 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -797,9 +797,11 @@  operator== (const dynamic_prop &l, const dynamic_prop &r)
     case PROP_CONST:
       return l.const_val () == r.const_val ();
     case PROP_FIELD:
+      return l.field () == r.field ();
     case PROP_LOCEXPR:
+      return l.locexpr () == r.locexpr ();
     case PROP_LOCLIST:
-      return l.baton () == r.baton ();
+      return l.loclist () == r.loclist ();
     case PROP_VARIANT_PARTS:
       return l.variant_parts () == r.variant_parts ();
     case PROP_TYPE:
@@ -2666,12 +2668,9 @@  resolve_dynamic_field (struct field &field,
 
   if (field.loc_is_dwarf_block ())
     {
-      dwarf2_locexpr_baton *field_loc
-	= field.loc_dwarf_block ();
-
-      struct dwarf2_property_baton baton;
-      baton.property_type = lookup_pointer_type (field.type ());
-      baton.locexpr = *field_loc;
+      dwarf2_locexpr_baton *field_loc = field.loc_dwarf_block ();
+      dwarf2_locexpr_property_baton baton
+	(*lookup_pointer_type (field.type ()), *field_loc);
 
       struct dynamic_prop prop;
       prop.set_locexpr (&baton);
@@ -4221,8 +4220,7 @@  check_types_equal (struct type *type1, struct type *type2,
 		block1 = field1->loc_dwarf_block ();
 		block2 = field2->loc_dwarf_block ();
 		if (block1->per_cu != block2->per_cu
-		    || block1->size != block2->size
-		    || memcmp (block1->data, block2->data, block1->size) != 0)
+		    || block1->expr != block2->expr)
 		  return false;
 	      }
 	      break;
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index b32056ce530c..010df3fda7ea 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -59,6 +59,9 @@  struct language_defn;
 struct dwarf2_per_cu;
 struct dwarf2_per_objfile;
 struct dwarf2_property_baton;
+struct dwarf2_locexpr_property_baton;
+struct dwarf2_loclist_property_baton;
+struct dwarf2_field_property_baton;
 
 /* * Different kinds of data types are distinguished by the `code'
    field.  */
@@ -344,31 +347,49 @@  struct dynamic_prop
   bool is_constant () const
   { return m_kind == PROP_CONST; }
 
-  const dwarf2_property_baton *baton () const
-  {
-    gdb_assert (m_kind == PROP_LOCEXPR
-		|| m_kind == PROP_LOCLIST
-		|| m_kind == PROP_FIELD);
+  /* We need to use reinterpret_cast below instead of static_cast below, because
+     the baton types are not complete, and including dwarf2/loc.h would cause a
+     cyclic dependency.  */
 
-    return m_data.baton;
+  const dwarf2_locexpr_property_baton *locexpr () const
+  {
+    gdb_assert (m_kind == PROP_LOCEXPR);
+
+    return (reinterpret_cast<const dwarf2_locexpr_property_baton *>
+	    (m_data.baton));
   }
 
-  void set_locexpr (const dwarf2_property_baton *baton)
+  const dwarf2_loclist_property_baton *loclist () const
+  {
+    gdb_assert (m_kind == PROP_LOCLIST);
+
+    return (reinterpret_cast<const dwarf2_loclist_property_baton *>
+	    (m_data.baton));
+  }
+
+  const dwarf2_field_property_baton *field () const
+  {
+    gdb_assert (m_kind == PROP_FIELD);
+
+    return reinterpret_cast<const dwarf2_field_property_baton *> (m_data.baton);
+  }
+
+  void set_locexpr (const dwarf2_locexpr_property_baton *baton)
   {
     m_kind = PROP_LOCEXPR;
-    m_data.baton = baton;
+    m_data.baton = reinterpret_cast<const dwarf2_property_baton *> (baton);
   }
 
-  void set_loclist (const dwarf2_property_baton *baton)
+  void set_loclist (const dwarf2_loclist_property_baton *baton)
   {
     m_kind = PROP_LOCLIST;
-    m_data.baton = baton;
+    m_data.baton = reinterpret_cast<const dwarf2_property_baton *> (baton);
   }
 
-  void set_field (const dwarf2_property_baton *baton)
+  void set_field (const dwarf2_field_property_baton *baton)
   {
     m_kind = PROP_FIELD;
-    m_data.baton = baton;
+    m_data.baton = reinterpret_cast<const dwarf2_property_baton *> (baton);
   }
 
   const gdb::array_view<variant_part> *variant_parts () const
diff --git a/gdb/gnu-v3-abi.c b/gdb/gnu-v3-abi.c
index 35910be0f06d..1270a5d34ba4 100644
--- a/gdb/gnu-v3-abi.c
+++ b/gdb/gnu-v3-abi.c
@@ -478,10 +478,10 @@  gnuv3_baseclass_offset (struct type *type, int index,
   /* If we have a DWARF expression for the offset, evaluate it.  */
   if (type->field (index).loc_kind () == FIELD_LOC_KIND_DWARF_BLOCK_ADDR)
     {
-      struct dwarf2_property_baton baton;
-      baton.property_type
+      struct type *property_type
 	= lookup_pointer_type (type->field (index).type ());
-      baton.locexpr = *type->field (index).loc_dwarf_block ();
+      dwarf2_locexpr_baton *locexpr = type->field (index).loc_dwarf_block ();
+      dwarf2_locexpr_property_baton baton (*property_type, *locexpr);
 
       struct dynamic_prop prop;
       prop.set_locexpr (&baton);