diff mbox series

[RFC,v4,08/15] GDB: Allow DWARF expression evaluation to use regcache

Message ID 20241102025635.586759-9-thiago.bauermann@linaro.org
State New
Headers show
Series gdbserver improvements for AArch64 SVE support | expand

Commit Message

Thiago Jung Bauermann Nov. 2, 2024, 2:56 a.m. UTC
Currently, expression evaluation is done in the context of a frame.
However, for variable-size registers we will need to evaluate
expressions when no frame is available, but we do have a regcache.
Therefore, allow passing a regcache to dwarf2_evaluate_property.

This requires adding a regcache parameter to resolve_dynamic_type and
its internal functions.

Also, this means that a DWARF expression may not be associated with an
objfile, so when it needs a gdbarch it may not be possible to get the
one from the objfile.  The solution is to add an m_gdbarch member to
dwarf_expr_context, and make it point to the gdbarch of either the
objfile, frame or regcache associated with the expression.

Simon suggested using GDB Agent Expressions rather than DWARF
expressions to encode the register length. I will try it out, and if it
works then this patch can be dropped.
---
 gdb/dwarf2/expr.c  | 63 +++++++++++++++++++++++++++++++------
 gdb/dwarf2/expr.h  | 17 +++++++++-
 gdb/dwarf2/frame.c |  2 +-
 gdb/dwarf2/loc.c   | 41 +++++++++++++++++-------
 gdb/dwarf2/loc.h   |  2 ++
 gdb/findvar.c      | 17 ++++++++++
 gdb/frame.c        |  3 +-
 gdb/gdbtypes.c     | 77 ++++++++++++++++++++++++++--------------------
 gdb/gdbtypes.h     |  5 ++-
 gdb/gnu-v3-abi.c   |  2 +-
 gdb/value.h        |  3 ++
 11 files changed, 173 insertions(+), 59 deletions(-)

Comments

Luis Machado Dec. 16, 2024, 4:56 p.m. UTC | #1
On 11/2/24 02:56, Thiago Jung Bauermann wrote:
> Currently, expression evaluation is done in the context of a frame.
> However, for variable-size registers we will need to evaluate
> expressions when no frame is available, but we do have a regcache.
> Therefore, allow passing a regcache to dwarf2_evaluate_property.
> 
> This requires adding a regcache parameter to resolve_dynamic_type and
> its internal functions.
> 
> Also, this means that a DWARF expression may not be associated with an
> objfile, so when it needs a gdbarch it may not be possible to get the
> one from the objfile.  The solution is to add an m_gdbarch member to
> dwarf_expr_context, and make it point to the gdbarch of either the
> objfile, frame or regcache associated with the expression.
> 
> Simon suggested using GDB Agent Expressions rather than DWARF
> expressions to encode the register length. I will try it out, and if it
> works then this patch can be dropped.

Between using DWARF expressions and agent expressions, I suppose DWARF would
be the most promising as it is properly documented. Agent expressions are a
bit obscure at this point I think, and IIRC gdb-specific. But if it provides
something simpler, might be worth a shot.

> ---
>  gdb/dwarf2/expr.c  | 63 +++++++++++++++++++++++++++++++------
>  gdb/dwarf2/expr.h  | 17 +++++++++-
>  gdb/dwarf2/frame.c |  2 +-
>  gdb/dwarf2/loc.c   | 41 +++++++++++++++++-------
>  gdb/dwarf2/loc.h   |  2 ++
>  gdb/findvar.c      | 17 ++++++++++
>  gdb/frame.c        |  3 +-
>  gdb/gdbtypes.c     | 77 ++++++++++++++++++++++++++--------------------
>  gdb/gdbtypes.h     |  5 ++-
>  gdb/gnu-v3-abi.c   |  2 +-
>  gdb/value.h        |  3 ++
>  11 files changed, 173 insertions(+), 59 deletions(-)
> 
> diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
> index 5ad17eaaaff8..4a667dbd8107 100644
> --- a/gdb/dwarf2/expr.c
> +++ b/gdb/dwarf2/expr.c
> @@ -56,6 +56,20 @@ ensure_have_frame (const frame_info_ptr &frame, const char *op_name)
>  		 _("%s evaluation requires a frame."), op_name);
>  }
>  
> +/* Ensure that either a FRAME or a REGCACHE is defined, throw an exception
> +   otherwise.  */
> +
> +static void
> +ensure_have_frame_or_regcache (const frame_info_ptr &frame,
> +			       const reg_buffer *regcache,
> +			       const char *op_name)
> +{
> +  if (frame == nullptr && regcache == nullptr)
> +    throw_error (GENERIC_ERROR,
> +		 _("%s evaluation requires a frame or register cache."),
> +		 op_name);
> +}
> +
>  /* Ensure that a PER_CU is defined and throw an exception otherwise.  */
>  
>  static void
> @@ -86,6 +100,16 @@ read_addr_from_reg (const frame_info_ptr &frame, int reg)
>    return address_from_register (regnum, frame);
>  }
>  
> +/* See expr.h.  */
> +
> +CORE_ADDR
> +read_addr_from_reg (reg_buffer *regcache, int reg)
> +{
> +  int regnum = dwarf_reg_to_regnum_or_error (regcache->arch (), reg);
> +
> +  return address_from_register (regnum, regcache);
> +}
> +
>  struct piece_closure
>  {
>    /* Reference count.  */
> @@ -690,7 +714,8 @@ sect_variable_value (sect_offset sect_off,
>  struct type *
>  dwarf_expr_context::address_type () const
>  {
> -  gdbarch *arch = this->m_per_objfile->objfile->arch ();
> +  gdbarch *arch = (m_gdbarch == nullptr ? this->m_per_objfile->objfile->arch ()
> +		   : m_gdbarch);
>    dwarf_gdbarch_types *types = dwarf_arch_cookie.get (arch);
>    if (types == nullptr)
>      types = dwarf_arch_cookie.emplace (arch);
> @@ -720,9 +745,11 @@ dwarf_expr_context::address_type () const
>  /* Create a new context for the expression evaluator.  */
>  
>  dwarf_expr_context::dwarf_expr_context (dwarf2_per_objfile *per_objfile,
> -					int addr_size)
> +					int addr_size,
> +					gdbarch *gdbarch)
>  : m_addr_size (addr_size),
> -  m_per_objfile (per_objfile)
> +  m_per_objfile (per_objfile),
> +  m_gdbarch (gdbarch)
>  {
>  }
>  
> @@ -915,7 +942,6 @@ dwarf_expr_context::fetch_result (struct type *type, struct type *subobj_type,
>  				  LONGEST subobj_offset, bool as_lval)
>  {
>    value *retval = nullptr;
> -  gdbarch *arch = this->m_per_objfile->objfile->arch ();
>  
>    if (type == nullptr)
>      type = address_type ();
> @@ -948,6 +974,9 @@ dwarf_expr_context::fetch_result (struct type *type, struct type *subobj_type,
>      }
>    else
>      {
> +      gdbarch *arch = (m_gdbarch == nullptr ? this->m_per_objfile->objfile->arch ()
> +		       : m_gdbarch);
> +
>        /* If AS_LVAL is false, means that the implicit conversion
>  	 from a location description to value is expected.  */
>        if (!as_lval)
> @@ -1077,12 +1106,14 @@ dwarf_expr_context::fetch_result (struct type *type, struct type *subobj_type,
>  value *
>  dwarf_expr_context::evaluate (const gdb_byte *addr, size_t len, bool as_lval,
>  			      dwarf2_per_cu_data *per_cu, const frame_info_ptr &frame,
> +			      reg_buffer *regcache,
>  			      const struct property_addr_info *addr_info,
>  			      struct type *type, struct type *subobj_type,
>  			      LONGEST subobj_offset)
>  {
>    this->m_per_cu = per_cu;
>    this->m_frame = frame;
> +  this->m_regcache = regcache;
>    this->m_addr_info = addr_info;
>  
>    eval (addr, len);
> @@ -1149,7 +1180,8 @@ get_signed_type (struct gdbarch *gdbarch, struct type *type)
>  CORE_ADDR
>  dwarf_expr_context::fetch_address (int n)
>  {
> -  gdbarch *arch = this->m_per_objfile->objfile->arch ();
> +  gdbarch *arch = (m_gdbarch == nullptr ? this->m_per_objfile->objfile->arch ()
> +		   : m_gdbarch);
>    value *result_val = fetch (n);
>    bfd_endian byte_order = gdbarch_byte_order (arch);
>    ULONGEST result;
> @@ -1493,7 +1525,8 @@ void
>  dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
>  				      const gdb_byte *op_end)
>  {
> -  gdbarch *arch = this->m_per_objfile->objfile->arch ();
> +  gdbarch *arch = (this->m_gdbarch ? this->m_gdbarch
> +		   : this->m_per_objfile->objfile->arch ());
>    bfd_endian byte_order = gdbarch_byte_order (arch);
>    /* Old-style "untyped" DWARF values need special treatment in a
>       couple of places, specifically DW_OP_mod and DW_OP_shr.  We need
> @@ -1784,9 +1817,14 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
>  	case DW_OP_breg31:
>  	  {
>  	    op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
> -	    ensure_have_frame (this->m_frame, "DW_OP_breg");
> +	    ensure_have_frame_or_regcache (this->m_frame, this->m_regcache,
> +					   "DW_OP_breg");
> +
> +	    if (this->m_frame != nullptr)
> +	      result = read_addr_from_reg (this->m_frame, op - DW_OP_breg0);
> +	    else
> +	      result = read_addr_from_reg (this->m_regcache, op - DW_OP_breg0);
>  
> -	    result = read_addr_from_reg (this->m_frame, op - DW_OP_breg0);
>  	    result += offset;
>  	    result_val = value_from_ulongest (address_type, result);
>  	  }
> @@ -1795,9 +1833,14 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
>  	  {
>  	    op_ptr = safe_read_uleb128 (op_ptr, op_end, &reg);
>  	    op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
> -	    ensure_have_frame (this->m_frame, "DW_OP_bregx");
> +	    ensure_have_frame_or_regcache (this->m_frame, this->m_regcache,
> +					   "DW_OP_bregx");
> +
> +	    if (this->m_frame != nullptr)
> +	      result = read_addr_from_reg (this->m_frame, reg);
> +	    else
> +	      result = read_addr_from_reg (this->m_regcache, reg);
>  
> -	    result = read_addr_from_reg (this->m_frame, reg);
>  	    result += offset;
>  	    result_val = value_from_ulongest (address_type, result);
>  	  }
> diff --git a/gdb/dwarf2/expr.h b/gdb/dwarf2/expr.h
> index b02cc5316406..9a3c92650664 100644
> --- a/gdb/dwarf2/expr.h
> +++ b/gdb/dwarf2/expr.h
> @@ -115,12 +115,14 @@ struct dwarf_stack_value
>    bool in_stack_memory;
>  };
>  
> +struct reg_buffer;
> +
>  /* The expression evaluator works with a dwarf_expr_context, describing
>     its current state and its callbacks.  */
>  struct dwarf_expr_context
>  {
>    dwarf_expr_context (dwarf2_per_objfile *per_objfile,
> -		      int addr_size);
> +		      int addr_size, gdbarch *gdbarch = nullptr);
>    virtual ~dwarf_expr_context () = default;
>  
>    void push_address (CORE_ADDR value, bool in_stack_memory);
> @@ -128,6 +130,8 @@ struct dwarf_expr_context
>    /* Evaluate the expression at ADDR (LEN bytes long) in a given PER_CU
>       and FRAME context.
>  
> +     If FRAME is nullptr, then registers are read from REGCACHE.
> +
>       AS_LVAL defines if the returned struct value is expected to be a
>       value (false) or a location description (true).
>  
> @@ -138,6 +142,7 @@ struct dwarf_expr_context
>       memory addresses with the passed in buffer.  */
>    value *evaluate (const gdb_byte *addr, size_t len, bool as_lval,
>  		   dwarf2_per_cu_data *per_cu, const frame_info_ptr &frame,
> +		   reg_buffer *regcache,
>  		   const struct property_addr_info *addr_info = nullptr,
>  		   struct type *type = nullptr,
>  		   struct type *subobj_type = nullptr,
> @@ -198,6 +203,12 @@ struct dwarf_expr_context
>    /* Frame information used for the evaluation.  */
>    frame_info_ptr m_frame = nullptr;
>  
> +  /* Register cache used for the evaluation, in case there's no frame.  */
> +  reg_buffer *m_regcache = nullptr;
> +
> +  /* gdbarch used for the evaluation.  */
> +  gdbarch *m_gdbarch = nullptr;
> +
>    /* Compilation unit used for the evaluation.  */
>    dwarf2_per_cu_data *m_per_cu = nullptr;
>  
> @@ -258,6 +269,10 @@ struct dwarf_expr_context
>     read as an address in a given FRAME.  */
>  CORE_ADDR read_addr_from_reg (const frame_info_ptr &frame, int reg);
>  
> +/* Return the value of register number REG (a DWARF register number),
> +   read as an address in a given REGCACHE.  */
> +CORE_ADDR read_addr_from_reg (reg_buffer *regcache, int reg);
> +
>  void dwarf_expr_require_composition (const gdb_byte *, const gdb_byte *,
>  				     const char *);
>  
> diff --git a/gdb/dwarf2/frame.c b/gdb/dwarf2/frame.c
> index 841d2d4a2fec..3da9551a7ace 100644
> --- a/gdb/dwarf2/frame.c
> +++ b/gdb/dwarf2/frame.c
> @@ -237,7 +237,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 (exp, len, true, nullptr, this_frame, nullptr);
>  
>    if (result_val->lval () == lval_memory)
>      return result_val->address ();
> diff --git a/gdb/dwarf2/loc.c b/gdb/dwarf2/loc.c
> index d5153862a01d..d7fa58047cdd 100644
> --- a/gdb/dwarf2/loc.c
> +++ b/gdb/dwarf2/loc.c
> @@ -1518,7 +1518,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,
> -			     type, subobj_type, subobj_byte_offset);
> +			     nullptr, type, subobj_type, subobj_byte_offset);
>      }
>    catch (const gdb_exception_error &ex)
>      {
> @@ -1565,11 +1565,12 @@ dwarf2_evaluate_loc_desc (struct type *type, const frame_info_ptr &frame,
>  					per_objfile, NULL, 0, as_lval);
>  }
>  
> -/* Evaluates a dwarf expression and stores the result in VAL,
> -   expecting that the dwarf expression only produces a single
> -   CORE_ADDR.  FRAME is the frame in which the expression is
> -   evaluated.  ADDR_STACK is a context (location of a variable) and
> -   might be needed to evaluate the location expression.
> +/* Evaluates a dwarf expression and stores the result in VAL, expecting
> +   that the dwarf expression only produces a single CORE_ADDR.  FRAME is
> +   the frame in which the expression is evaluated.  If FRAME is nullptr,
> +   then registers are read from REGCACHE instead.  ADDR_STACK is a context
> +   (location of a variable) and might be needed to evaluate the location
> +   expression.
>  
>     PUSH_VALUES is an array of values to be pushed to the expression stack
>     before evaluation starts.  PUSH_VALUES[0] is pushed first, then
> @@ -1580,6 +1581,7 @@ dwarf2_evaluate_loc_desc (struct type *type, const frame_info_ptr &frame,
>  static int
>  dwarf2_locexpr_baton_eval (const struct dwarf2_locexpr_baton *dlbaton,
>  			   const frame_info_ptr &frame,
> +			   reg_buffer *regcache,
>  			   const struct property_addr_info *addr_stack,
>  			   CORE_ADDR *valp,
>  			   gdb::array_view<CORE_ADDR> push_values,
> @@ -1590,7 +1592,21 @@ dwarf2_locexpr_baton_eval (const struct dwarf2_locexpr_baton *dlbaton,
>  
>    dwarf2_per_objfile *per_objfile = dlbaton->per_objfile;
>    dwarf2_per_cu_data *per_cu = dlbaton->per_cu;
> -  dwarf_expr_context ctx (per_objfile, per_cu->addr_size ());
> +  gdbarch *gdbarch;
> +
> +  if (per_objfile != nullptr)
> +    gdbarch = per_objfile->objfile->arch ();
> +  else if (frame != nullptr)
> +    gdbarch = get_frame_arch (frame);
> +  else
> +    {
> +      gdb_assert (regcache != nullptr);
> +      gdbarch = regcache->arch ();
> +    }
> +
> +  int addr_size = (per_cu == nullptr ? gdbarch_addr_bit (gdbarch) / 8
> +		   : per_cu->addr_size ());
> +  dwarf_expr_context ctx (per_objfile, addr_size, gdbarch);
>  
>    value *result;
>    scoped_value_mark free_values;
> @@ -1602,7 +1618,7 @@ dwarf2_locexpr_baton_eval (const struct dwarf2_locexpr_baton *dlbaton,
>    try
>      {
>        result = ctx.evaluate (dlbaton->data, dlbaton->size,
> -			     true, per_cu, frame, addr_stack);
> +			     true, per_cu, frame, regcache, addr_stack);
>      }
>    catch (const gdb_exception_error &ex)
>      {
> @@ -1641,6 +1657,7 @@ dwarf2_locexpr_baton_eval (const struct dwarf2_locexpr_baton *dlbaton,
>  bool
>  dwarf2_evaluate_property (const dynamic_prop *prop,
>  			  const frame_info_ptr &initial_frame,
> +			  reg_buffer *regcache,
>  			  const property_addr_info *addr_stack,
>  			  CORE_ADDR *value,
>  			  gdb::array_view<CORE_ADDR> push_values)
> @@ -1654,7 +1671,8 @@ dwarf2_evaluate_property (const dynamic_prop *prop,
>    scoped_restore_current_language save_language;
>    frame_info_ptr frame = initial_frame;
>  
> -  if (frame == NULL && has_stack_frames ())
> +  /* Only try to get a frame if no regcache was provided.  */
> +  if (frame == nullptr && regcache == nullptr && has_stack_frames ())
>      frame = get_selected_frame (NULL);
>  
>    switch (prop->kind ())
> @@ -1665,8 +1683,9 @@ dwarf2_evaluate_property (const dynamic_prop *prop,
>  	gdb_assert (baton->property_type != NULL);
>  
>  	bool is_reference = baton->locexpr.is_reference;
> -	if (dwarf2_locexpr_baton_eval (&baton->locexpr, frame, addr_stack,
> -				       value, push_values, &is_reference))
> +	if (dwarf2_locexpr_baton_eval (&baton->locexpr, frame, regcache,
> +				       addr_stack, value, push_values,
> +				       &is_reference))
>  	  {
>  	    if (is_reference)
>  	      {
> diff --git a/gdb/dwarf2/loc.h b/gdb/dwarf2/loc.h
> index 4fb743618e7c..679c4962d137 100644
> --- a/gdb/dwarf2/loc.h
> +++ b/gdb/dwarf2/loc.h
> @@ -118,8 +118,10 @@ struct property_addr_info
>     etc.  This means the during evaluation PUSH_VALUES[0] will be at the
>     bottom of the stack.  */
>  
> +struct reg_buffer;
>  bool dwarf2_evaluate_property (const struct dynamic_prop *prop,
>  			       const frame_info_ptr &frame,
> +			       reg_buffer *regcache,
>  			       const property_addr_info *addr_stack,
>  			       CORE_ADDR *value,
>  			       gdb::array_view<CORE_ADDR> push_values = {});
> diff --git a/gdb/findvar.c b/gdb/findvar.c
> index f7760aa61ca9..d65bf2fc278c 100644
> --- a/gdb/findvar.c
> +++ b/gdb/findvar.c
> @@ -656,3 +656,20 @@ address_from_register (int regnum, const frame_info_ptr &frame)
>  
>    return value_as_address (v.get ());
>  }
> +
> +/* Return contents of register REGNUM in REGCACHE as address.
> +   Will abort if register value is not available.  */
> +
> +CORE_ADDR
> +address_from_register (int regnum, reg_buffer *regcache)
> +{
> +  if (regcache->get_register_status (regnum) != REG_VALID)
> +    throw_error (NOT_AVAILABLE_ERROR, _("register %d is not available"),
> +		 regnum);
> +
> +  gdb_byte buffer[sizeof (CORE_ADDR)];
> +  regcache->raw_collect (regnum, buffer);
> +
> +  type *type = builtin_type (regcache->arch ())->builtin_data_ptr;
> +  return extract_typed_address (buffer, type);
> +}
> diff --git a/gdb/frame.c b/gdb/frame.c
> index 2c1ea012191b..663ff7fa773b 100644
> --- a/gdb/frame.c
> +++ b/gdb/frame.c
> @@ -3175,7 +3175,8 @@ frame_follow_static_link (const frame_info_ptr &initial_frame)
>  
>    CORE_ADDR upper_frame_base;
>  
> -  if (!dwarf2_evaluate_property (static_link, initial_frame, NULL, &upper_frame_base))
> +  if (!dwarf2_evaluate_property (static_link, initial_frame, nullptr, nullptr,
> +				 &upper_frame_base))
>      return {};
>  
>    /* Now climb up the stack frame until we reach the frame we are interested
> diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
> index 2a3aea229cb0..ea8bad4e826c 100644
> --- a/gdb/gdbtypes.c
> +++ b/gdb/gdbtypes.c
> @@ -2146,7 +2146,7 @@ is_dynamic_type (struct type *type)
>  
>  static struct type *resolve_dynamic_type_internal
>    (struct type *type, struct property_addr_info *addr_stack,
> -   const frame_info_ptr &frame, bool top_level);
> +   const frame_info_ptr &frame, reg_buffer *regcache, bool top_level);
>  
>  /* Given a dynamic range type (dyn_range_type) and a stack of
>     struct property_addr_info elements, return a static version
> @@ -2168,6 +2168,7 @@ static struct type *
>  resolve_dynamic_range (struct type *dyn_range_type,
>  		       struct property_addr_info *addr_stack,
>  		       const frame_info_ptr &frame,
> +		       reg_buffer *regcache,
>  		       int rank, bool resolve_p = true)
>  {
>    CORE_ADDR value;
> @@ -2180,7 +2181,7 @@ resolve_dynamic_range (struct type *dyn_range_type,
>    const struct dynamic_prop *prop = &dyn_range_type->bounds ()->low;
>    if (resolve_p)
>      {
> -      if (dwarf2_evaluate_property (prop, frame, addr_stack, &value,
> +      if (dwarf2_evaluate_property (prop, frame, regcache, addr_stack, &value,
>  				    { (CORE_ADDR) rank }))
>  	low_bound.set_const_val (value);
>        else if (prop->kind () == PROP_UNDEFINED)
> @@ -2194,7 +2195,7 @@ resolve_dynamic_range (struct type *dyn_range_type,
>    prop = &dyn_range_type->bounds ()->high;
>    if (resolve_p)
>      {
> -      if (dwarf2_evaluate_property (prop, frame, addr_stack, &value,
> +      if (dwarf2_evaluate_property (prop, frame, regcache, addr_stack, &value,
>  				    { (CORE_ADDR) rank }))
>  	{
>  	  high_bound.set_const_val (value);
> @@ -2213,8 +2214,8 @@ resolve_dynamic_range (struct type *dyn_range_type,
>  
>    bool byte_stride_p = dyn_range_type->bounds ()->flag_is_byte_stride;
>    prop = &dyn_range_type->bounds ()->stride;
> -  if (resolve_p && dwarf2_evaluate_property (prop, frame, addr_stack, &value,
> -					     { (CORE_ADDR) rank }))
> +  if (resolve_p && dwarf2_evaluate_property (prop, frame, regcache, addr_stack,
> +					     &value, { (CORE_ADDR) rank }))
>      {
>        stride.set_const_val (value);
>  
> @@ -2236,7 +2237,7 @@ resolve_dynamic_range (struct type *dyn_range_type,
>  
>    static_target_type
>      = resolve_dynamic_type_internal (dyn_range_type->target_type (),
> -				     addr_stack, frame, false);
> +				     addr_stack, frame, regcache, false);
>    LONGEST bias = dyn_range_type->bounds ()->bias;
>    type_allocator alloc (dyn_range_type);
>    static_range_type = create_range_type_with_stride
> @@ -2270,6 +2271,7 @@ static struct type *
>  resolve_dynamic_array_or_string_1 (struct type *type,
>  				   struct property_addr_info *addr_stack,
>  				   const frame_info_ptr &frame,
> +				   reg_buffer *regcache,
>  				   int rank, bool resolve_p)
>  {
>    CORE_ADDR value;
> @@ -2299,7 +2301,7 @@ resolve_dynamic_array_or_string_1 (struct type *type,
>       dimension of the array.  */
>    prop = TYPE_ALLOCATED_PROP (type);
>    if (prop != NULL && resolve_p
> -      && dwarf2_evaluate_property (prop, frame, addr_stack, &value))
> +      && dwarf2_evaluate_property (prop, frame, regcache, addr_stack, &value))
>      {
>        prop->set_const_val (value);
>        if (value == 0)
> @@ -2308,7 +2310,7 @@ resolve_dynamic_array_or_string_1 (struct type *type,
>  
>    prop = TYPE_ASSOCIATED_PROP (type);
>    if (prop != NULL && resolve_p
> -      && dwarf2_evaluate_property (prop, frame, addr_stack, &value))
> +      && dwarf2_evaluate_property (prop, frame, regcache, addr_stack, &value))
>      {
>        prop->set_const_val (value);
>        if (value == 0)
> @@ -2317,14 +2319,15 @@ resolve_dynamic_array_or_string_1 (struct type *type,
>  
>    range_type = check_typedef (type->index_type ());
>    range_type
> -    = resolve_dynamic_range (range_type, addr_stack, frame, rank, resolve_p);
> +    = resolve_dynamic_range (range_type, addr_stack, frame, regcache, rank,
> +			     resolve_p);
>  
>    ary_dim = check_typedef (type->target_type ());
>    if (ary_dim != NULL && ary_dim->code () == TYPE_CODE_ARRAY)
>      {
>        ary_dim = copy_type (ary_dim);
>        elt_type = resolve_dynamic_array_or_string_1 (ary_dim, addr_stack,
> -						    frame, rank - 1,
> +						    frame, regcache, rank - 1,
>  						    resolve_p);
>      }
>    else if (ary_dim != nullptr && ary_dim->code () == TYPE_CODE_STRING)
> @@ -2355,7 +2358,7 @@ resolve_dynamic_array_or_string_1 (struct type *type,
>  	 Fortran, and hope that this doesn't cause problems for anyone
>  	 else.  */
>        elt_type = resolve_dynamic_type_internal (type->target_type (),
> -						addr_stack, frame, 0);
> +						addr_stack, frame, regcache, 0);
>      }
>    else
>      elt_type = type->target_type ();
> @@ -2365,7 +2368,7 @@ resolve_dynamic_array_or_string_1 (struct type *type,
>      prop = nullptr;
>    if (prop != NULL && resolve_p)
>      {
> -      if (dwarf2_evaluate_property (prop, frame, addr_stack, &value))
> +      if (dwarf2_evaluate_property (prop, frame, regcache, addr_stack, &value))
>  	{
>  	  type->remove_dyn_prop (DYN_PROP_BYTE_STRIDE);
>  	  bit_stride = (unsigned int) (value * 8);
> @@ -2397,7 +2400,8 @@ resolve_dynamic_array_or_string_1 (struct type *type,
>  static struct type *
>  resolve_dynamic_array_or_string (struct type *type,
>  				 struct property_addr_info *addr_stack,
> -				 const frame_info_ptr &frame)
> +				 const frame_info_ptr &frame,
> +				 reg_buffer *regcache)
>  {
>    CORE_ADDR value;
>    int rank = 0;
> @@ -2411,7 +2415,7 @@ resolve_dynamic_array_or_string (struct type *type,
>  
>    /* Resolve the rank property to get rank value.  */
>    struct dynamic_prop *prop = TYPE_RANK_PROP (type);
> -  if (dwarf2_evaluate_property (prop, frame, addr_stack, &value))
> +  if (dwarf2_evaluate_property (prop, frame, regcache, addr_stack, &value))
>      {
>        prop->set_const_val (value);
>        rank = value;
> @@ -2479,8 +2483,8 @@ resolve_dynamic_array_or_string (struct type *type,
>       reduce the rank by 1 here.  */
>    --rank;
>  
> -  return resolve_dynamic_array_or_string_1 (type, addr_stack, frame, rank,
> -					    true);
> +  return resolve_dynamic_array_or_string_1 (type, addr_stack, frame, regcache,
> +					    rank, true);
>  }
>  
>  /* Resolve dynamic bounds of members of the union TYPE to static
> @@ -2490,7 +2494,8 @@ resolve_dynamic_array_or_string (struct type *type,
>  static struct type *
>  resolve_dynamic_union (struct type *type,
>  		       struct property_addr_info *addr_stack,
> -		       const frame_info_ptr &frame)
> +		       const frame_info_ptr &frame,
> +		       reg_buffer *regcache)
>  {
>    struct type *resolved_type;
>    int i;
> @@ -2508,7 +2513,7 @@ resolve_dynamic_union (struct type *type,
>  	continue;
>  
>        t = resolve_dynamic_type_internal (resolved_type->field (i).type (),
> -					 addr_stack, frame, false);
> +					 addr_stack, frame, regcache, false);
>        resolved_type->field (i).set_type (t);
>  
>        struct type *real_type = check_typedef (t);
> @@ -2682,7 +2687,8 @@ compute_variant_fields (struct type *type,
>  static struct type *
>  resolve_dynamic_struct (struct type *type,
>  			struct property_addr_info *addr_stack,
> -			const frame_info_ptr &frame)
> +			const frame_info_ptr &frame,
> +			reg_buffer *regcache)
>  {
>    struct type *resolved_type;
>    int i;
> @@ -2725,8 +2731,8 @@ resolve_dynamic_struct (struct type *type,
>  	  prop.set_locexpr (&baton);
>  
>  	  CORE_ADDR addr;
> -	  if (dwarf2_evaluate_property (&prop, frame, addr_stack, &addr,
> -					{addr_stack->addr}))
> +	  if (dwarf2_evaluate_property (&prop, frame, regcache, addr_stack,
> +					&addr, {addr_stack->addr}))
>  	    resolved_type->field (i).set_loc_bitpos
>  	      (TARGET_CHAR_BIT * (addr - addr_stack->addr));
>  	}
> @@ -2752,7 +2758,7 @@ resolve_dynamic_struct (struct type *type,
>  
>        resolved_type->field (i).set_type
>  	(resolve_dynamic_type_internal (resolved_type->field (i).type (),
> -					&pinfo, frame, false));
> +					&pinfo, frame, regcache, false));
>        gdb_assert (resolved_type->field (i).loc_kind ()
>  		  == FIELD_LOC_KIND_BITPOS);
>  
> @@ -2798,6 +2804,7 @@ static struct type *
>  resolve_dynamic_type_internal (struct type *type,
>  			       struct property_addr_info *addr_stack,
>  			       const frame_info_ptr &frame,
> +			       reg_buffer *regcache,
>  			       bool top_level)
>  {
>    struct type *real_type = check_typedef (type);
> @@ -2811,7 +2818,7 @@ resolve_dynamic_type_internal (struct type *type,
>    std::optional<CORE_ADDR> type_length;
>    prop = TYPE_DYNAMIC_LENGTH (type);
>    if (prop != NULL
> -      && dwarf2_evaluate_property (prop, frame, addr_stack, &value))
> +      && dwarf2_evaluate_property (prop, frame, regcache, addr_stack, &value))
>      type_length = value;
>  
>    if (type->code () == TYPE_CODE_TYPEDEF)
> @@ -2819,7 +2826,7 @@ resolve_dynamic_type_internal (struct type *type,
>        resolved_type = copy_type (type);
>        resolved_type->set_target_type
>  	(resolve_dynamic_type_internal (type->target_type (), addr_stack,
> -					frame, top_level));
> +					frame, regcache, top_level));
>      }
>    else
>      {
> @@ -2849,8 +2856,8 @@ resolve_dynamic_type_internal (struct type *type,
>  	      {
>  		resolved_type = copy_type (type);
>  		resolved_type->set_target_type
> -		  (resolve_dynamic_type_internal (type->target_type (),
> -						  &pinfo, frame, true));
> +		  (resolve_dynamic_type_internal (type->target_type (), &pinfo,
> +						  frame, regcache, true));
>  	      }
>  	    break;
>  	  }
> @@ -2860,7 +2867,7 @@ resolve_dynamic_type_internal (struct type *type,
>  	     treated as one here.  */
>  	case TYPE_CODE_ARRAY:
>  	  resolved_type = resolve_dynamic_array_or_string (type, addr_stack,
> -							   frame);
> +							   frame, regcache);
>  	  break;
>  
>  	case TYPE_CODE_RANGE:
> @@ -2869,15 +2876,18 @@ resolve_dynamic_type_internal (struct type *type,
>  	     this rank value is not actually required for the resolution of
>  	     the dynamic range, otherwise, we'd be resolving this range
>  	     within the context of a dynamic array.  */
> -	  resolved_type = resolve_dynamic_range (type, addr_stack, frame, 0);
> +	  resolved_type = resolve_dynamic_range (type, addr_stack, frame,
> +						 regcache, 0);
>  	  break;
>  
>  	case TYPE_CODE_UNION:
> -	  resolved_type = resolve_dynamic_union (type, addr_stack, frame);
> +	  resolved_type = resolve_dynamic_union (type, addr_stack, frame,
> +						 regcache);
>  	  break;
>  
>  	case TYPE_CODE_STRUCT:
> -	  resolved_type = resolve_dynamic_struct (type, addr_stack, frame);
> +	  resolved_type = resolve_dynamic_struct (type, addr_stack, frame,
> +						  regcache);
>  	  break;
>  	}
>      }
> @@ -2894,7 +2904,7 @@ resolve_dynamic_type_internal (struct type *type,
>    /* Resolve data_location attribute.  */
>    prop = TYPE_DATA_LOCATION (resolved_type);
>    if (prop != NULL
> -      && dwarf2_evaluate_property (prop, frame, addr_stack, &value))
> +      && dwarf2_evaluate_property (prop, frame, regcache, addr_stack, &value))
>      {
>        /* Start of Fortran hack.  See comment in f-lang.h for what is going
>  	 on here.*/
> @@ -2915,7 +2925,8 @@ struct type *
>  resolve_dynamic_type (struct type *type,
>  		      gdb::array_view<const gdb_byte> valaddr,
>  		      CORE_ADDR addr,
> -		      const frame_info_ptr *in_frame)
> +		      const frame_info_ptr *in_frame,
> +		      reg_buffer *regcache)
>  {
>    struct property_addr_info pinfo
>      = {check_typedef (type), valaddr, addr, NULL};
> @@ -2924,7 +2935,7 @@ resolve_dynamic_type (struct type *type,
>    if (in_frame != nullptr)
>      frame = *in_frame;
>  
> -  return resolve_dynamic_type_internal (type, &pinfo, frame, true);
> +  return resolve_dynamic_type_internal (type, &pinfo, frame, regcache, true);
>  }
>  
>  /* See gdbtypes.h  */
> diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
> index f80bd7e071a3..514af300de3b 100644
> --- a/gdb/gdbtypes.h
> +++ b/gdb/gdbtypes.h
> @@ -2625,9 +2625,12 @@ extern CORE_ADDR get_pointer_type_max (struct type *);
>     have a different type when resolved (depending on the contents of
>     memory).  In this situation, 'is_dynamic_type' will still return
>     true for the return value of this function.  */
> +
> +struct reg_buffer;
>  extern struct type *resolve_dynamic_type
>    (struct type *type, gdb::array_view<const gdb_byte> valaddr,
> -   CORE_ADDR addr, const frame_info_ptr *frame = nullptr);
> +   CORE_ADDR addr, const frame_info_ptr *frame = nullptr,
> +   reg_buffer *regcache = nullptr);
>  
>  /* * Predicate if the type has dynamic values, which are not resolved yet.
>     See the caveat in 'resolve_dynamic_type' to understand a scenario
> diff --git a/gdb/gnu-v3-abi.c b/gdb/gnu-v3-abi.c
> index aefbee542703..5cc0d1d2d4f4 100644
> --- a/gdb/gnu-v3-abi.c
> +++ b/gdb/gnu-v3-abi.c
> @@ -493,7 +493,7 @@ gnuv3_baseclass_offset (struct type *type, int index,
>        addr_stack.next = nullptr;
>  
>        CORE_ADDR result;
> -      if (dwarf2_evaluate_property (&prop, nullptr, &addr_stack, &result,
> +      if (dwarf2_evaluate_property (&prop, nullptr, nullptr, &addr_stack, &result,
>  				    {addr_stack.addr}))
>  	return (int) (result - addr_stack.addr);
>      }
> diff --git a/gdb/value.h b/gdb/value.h
> index 13cfb007aa2c..802a49066288 100644
> --- a/gdb/value.h
> +++ b/gdb/value.h
> @@ -1133,6 +1133,9 @@ extern struct value *value_from_register (struct type *type, int regnum,
>  
>  extern CORE_ADDR address_from_register (int regnum,
>  					const frame_info_ptr &frame);
> +struct reg_buffer;
> +extern CORE_ADDR address_from_register (int regnum,
> +					reg_buffer *regcache);
>  
>  extern struct value *value_of_variable (struct symbol *var,
>  					const struct block *b);
Thiago Jung Bauermann Dec. 18, 2024, 3:26 a.m. UTC | #2
Luis Machado <luis.machado@arm.com> writes:

> On 11/2/24 02:56, Thiago Jung Bauermann wrote:
>> Currently, expression evaluation is done in the context of a frame.
>> However, for variable-size registers we will need to evaluate
>> expressions when no frame is available, but we do have a regcache.
>> Therefore, allow passing a regcache to dwarf2_evaluate_property.
>>
>> This requires adding a regcache parameter to resolve_dynamic_type and
>> its internal functions.
>>
>> Also, this means that a DWARF expression may not be associated with an
>> objfile, so when it needs a gdbarch it may not be possible to get the
>> one from the objfile.  The solution is to add an m_gdbarch member to
>> dwarf_expr_context, and make it point to the gdbarch of either the
>> objfile, frame or regcache associated with the expression.
>>
>> Simon suggested using GDB Agent Expressions rather than DWARF
>> expressions to encode the register length. I will try it out, and if it
>> works then this patch can be dropped.
>
> Between using DWARF expressions and agent expressions, I suppose DWARF would
> be the most promising as it is properly documented. Agent expressions are a
> bit obscure at this point I think, and IIRC gdb-specific. But if it provides
> something simpler, might be worth a shot.

I agree. I'll experiment with agent expressions and report back.

--
Thiago
Gerlicher, Klaus Feb. 13, 2025, 6:18 a.m. UTC | #3
Hi Thiago,

Given that you are already considering agent expressions, this reply maybe be of limited value but I'd still like to point out that DWARF expressions require that the register to be evaluated be a DWARF register which is only true for a subset of all registers in an architecture. For example, for Intel GPU the register controlling vector length is not a DWARF mapped register. Therefore we would have a hard time using this approach.

Thanks
Klaus


> -----Original Message-----
> From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
> Sent: Saturday, November 2, 2024 3:56 AM
> To: gdb-patches@sourceware.org
> Subject: [RFC PATCH v4 08/15] GDB: Allow DWARF expression evaluation to
> use regcache
> 
> Currently, expression evaluation is done in the context of a frame.
> However, for variable-size registers we will need to evaluate
> expressions when no frame is available, but we do have a regcache.
> Therefore, allow passing a regcache to dwarf2_evaluate_property.
> 
> This requires adding a regcache parameter to resolve_dynamic_type and
> its internal functions.
> 
> Also, this means that a DWARF expression may not be associated with an
> objfile, so when it needs a gdbarch it may not be possible to get the
> one from the objfile.  The solution is to add an m_gdbarch member to
> dwarf_expr_context, and make it point to the gdbarch of either the
> objfile, frame or regcache associated with the expression.
> 
> Simon suggested using GDB Agent Expressions rather than DWARF
> expressions to encode the register length. I will try it out, and if it
> works then this patch can be dropped.
> ---
>  gdb/dwarf2/expr.c  | 63 +++++++++++++++++++++++++++++++------
>  gdb/dwarf2/expr.h  | 17 +++++++++-
>  gdb/dwarf2/frame.c |  2 +-
>  gdb/dwarf2/loc.c   | 41 +++++++++++++++++-------
>  gdb/dwarf2/loc.h   |  2 ++
>  gdb/findvar.c      | 17 ++++++++++
>  gdb/frame.c        |  3 +-
>  gdb/gdbtypes.c     | 77 ++++++++++++++++++++++++++--------------------
>  gdb/gdbtypes.h     |  5 ++-
>  gdb/gnu-v3-abi.c   |  2 +-
>  gdb/value.h        |  3 ++
>  11 files changed, 173 insertions(+), 59 deletions(-)
> 
> diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
> index 5ad17eaaaff8..4a667dbd8107 100644
> --- a/gdb/dwarf2/expr.c
> +++ b/gdb/dwarf2/expr.c
> @@ -56,6 +56,20 @@ ensure_have_frame (const frame_info_ptr &frame,
> const char *op_name)
>  		 _("%s evaluation requires a frame."), op_name);
>  }
> 
> +/* Ensure that either a FRAME or a REGCACHE is defined, throw an exception
> +   otherwise.  */
> +
> +static void
> +ensure_have_frame_or_regcache (const frame_info_ptr &frame,
> +			       const reg_buffer *regcache,
> +			       const char *op_name)
> +{
> +  if (frame == nullptr && regcache == nullptr)
> +    throw_error (GENERIC_ERROR,
> +		 _("%s evaluation requires a frame or register cache."),
> +		 op_name);
> +}
> +
>  /* Ensure that a PER_CU is defined and throw an exception otherwise.  */
> 
>  static void
> @@ -86,6 +100,16 @@ read_addr_from_reg (const frame_info_ptr &frame,
> int reg)
>    return address_from_register (regnum, frame);
>  }
> 
> +/* See expr.h.  */
> +
> +CORE_ADDR
> +read_addr_from_reg (reg_buffer *regcache, int reg)
> +{
> +  int regnum = dwarf_reg_to_regnum_or_error (regcache->arch (), reg);
> +
> +  return address_from_register (regnum, regcache);
> +}
> +
>  struct piece_closure
>  {
>    /* Reference count.  */
> @@ -690,7 +714,8 @@ sect_variable_value (sect_offset sect_off,
>  struct type *
>  dwarf_expr_context::address_type () const
>  {
> -  gdbarch *arch = this->m_per_objfile->objfile->arch ();
> +  gdbarch *arch = (m_gdbarch == nullptr ? this->m_per_objfile->objfile->arch
> ()
> +		   : m_gdbarch);
>    dwarf_gdbarch_types *types = dwarf_arch_cookie.get (arch);
>    if (types == nullptr)
>      types = dwarf_arch_cookie.emplace (arch);
> @@ -720,9 +745,11 @@ dwarf_expr_context::address_type () const
>  /* Create a new context for the expression evaluator.  */
> 
>  dwarf_expr_context::dwarf_expr_context (dwarf2_per_objfile *per_objfile,
> -					int addr_size)
> +					int addr_size,
> +					gdbarch *gdbarch)
>  : m_addr_size (addr_size),
> -  m_per_objfile (per_objfile)
> +  m_per_objfile (per_objfile),
> +  m_gdbarch (gdbarch)
>  {
>  }
> 
> @@ -915,7 +942,6 @@ dwarf_expr_context::fetch_result (struct type *type,
> struct type *subobj_type,
>  				  LONGEST subobj_offset, bool as_lval)
>  {
>    value *retval = nullptr;
> -  gdbarch *arch = this->m_per_objfile->objfile->arch ();
> 
>    if (type == nullptr)
>      type = address_type ();
> @@ -948,6 +974,9 @@ dwarf_expr_context::fetch_result (struct type *type,
> struct type *subobj_type,
>      }
>    else
>      {
> +      gdbarch *arch = (m_gdbarch == nullptr ? this->m_per_objfile->objfile-
> >arch ()
> +		       : m_gdbarch);
> +
>        /* If AS_LVAL is false, means that the implicit conversion
>  	 from a location description to value is expected.  */
>        if (!as_lval)
> @@ -1077,12 +1106,14 @@ dwarf_expr_context::fetch_result (struct type
> *type, struct type *subobj_type,
>  value *
>  dwarf_expr_context::evaluate (const gdb_byte *addr, size_t len, bool as_lval,
>  			      dwarf2_per_cu_data *per_cu, const
> frame_info_ptr &frame,
> +			      reg_buffer *regcache,
>  			      const struct property_addr_info *addr_info,
>  			      struct type *type, struct type *subobj_type,
>  			      LONGEST subobj_offset)
>  {
>    this->m_per_cu = per_cu;
>    this->m_frame = frame;
> +  this->m_regcache = regcache;
>    this->m_addr_info = addr_info;
> 
>    eval (addr, len);
> @@ -1149,7 +1180,8 @@ get_signed_type (struct gdbarch *gdbarch, struct
> type *type)
>  CORE_ADDR
>  dwarf_expr_context::fetch_address (int n)
>  {
> -  gdbarch *arch = this->m_per_objfile->objfile->arch ();
> +  gdbarch *arch = (m_gdbarch == nullptr ? this->m_per_objfile->objfile->arch
> ()
> +		   : m_gdbarch);
>    value *result_val = fetch (n);
>    bfd_endian byte_order = gdbarch_byte_order (arch);
>    ULONGEST result;
> @@ -1493,7 +1525,8 @@ void
>  dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
>  				      const gdb_byte *op_end)
>  {
> -  gdbarch *arch = this->m_per_objfile->objfile->arch ();
> +  gdbarch *arch = (this->m_gdbarch ? this->m_gdbarch
> +		   : this->m_per_objfile->objfile->arch ());
>    bfd_endian byte_order = gdbarch_byte_order (arch);
>    /* Old-style "untyped" DWARF values need special treatment in a
>       couple of places, specifically DW_OP_mod and DW_OP_shr.  We need
> @@ -1784,9 +1817,14 @@ dwarf_expr_context::execute_stack_op (const
> gdb_byte *op_ptr,
>  	case DW_OP_breg31:
>  	  {
>  	    op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
> -	    ensure_have_frame (this->m_frame, "DW_OP_breg");
> +	    ensure_have_frame_or_regcache (this->m_frame, this-
> >m_regcache,
> +					   "DW_OP_breg");
> +
> +	    if (this->m_frame != nullptr)
> +	      result = read_addr_from_reg (this->m_frame, op - DW_OP_breg0);
> +	    else
> +	      result = read_addr_from_reg (this->m_regcache, op -
> DW_OP_breg0);
> 
> -	    result = read_addr_from_reg (this->m_frame, op - DW_OP_breg0);
>  	    result += offset;
>  	    result_val = value_from_ulongest (address_type, result);
>  	  }
> @@ -1795,9 +1833,14 @@ dwarf_expr_context::execute_stack_op (const
> gdb_byte *op_ptr,
>  	  {
>  	    op_ptr = safe_read_uleb128 (op_ptr, op_end, &reg);
>  	    op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
> -	    ensure_have_frame (this->m_frame, "DW_OP_bregx");
> +	    ensure_have_frame_or_regcache (this->m_frame, this-
> >m_regcache,
> +					   "DW_OP_bregx");
> +
> +	    if (this->m_frame != nullptr)
> +	      result = read_addr_from_reg (this->m_frame, reg);
> +	    else
> +	      result = read_addr_from_reg (this->m_regcache, reg);
> 
> -	    result = read_addr_from_reg (this->m_frame, reg);
>  	    result += offset;
>  	    result_val = value_from_ulongest (address_type, result);
>  	  }
> diff --git a/gdb/dwarf2/expr.h b/gdb/dwarf2/expr.h
> index b02cc5316406..9a3c92650664 100644
> --- a/gdb/dwarf2/expr.h
> +++ b/gdb/dwarf2/expr.h
> @@ -115,12 +115,14 @@ struct dwarf_stack_value
>    bool in_stack_memory;
>  };
> 
> +struct reg_buffer;
> +
>  /* The expression evaluator works with a dwarf_expr_context, describing
>     its current state and its callbacks.  */
>  struct dwarf_expr_context
>  {
>    dwarf_expr_context (dwarf2_per_objfile *per_objfile,
> -		      int addr_size);
> +		      int addr_size, gdbarch *gdbarch = nullptr);
>    virtual ~dwarf_expr_context () = default;
> 
>    void push_address (CORE_ADDR value, bool in_stack_memory);
> @@ -128,6 +130,8 @@ struct dwarf_expr_context
>    /* Evaluate the expression at ADDR (LEN bytes long) in a given PER_CU
>       and FRAME context.
> 
> +     If FRAME is nullptr, then registers are read from REGCACHE.
> +
>       AS_LVAL defines if the returned struct value is expected to be a
>       value (false) or a location description (true).
> 
> @@ -138,6 +142,7 @@ struct dwarf_expr_context
>       memory addresses with the passed in buffer.  */
>    value *evaluate (const gdb_byte *addr, size_t len, bool as_lval,
>  		   dwarf2_per_cu_data *per_cu, const frame_info_ptr &frame,
> +		   reg_buffer *regcache,
>  		   const struct property_addr_info *addr_info = nullptr,
>  		   struct type *type = nullptr,
>  		   struct type *subobj_type = nullptr,
> @@ -198,6 +203,12 @@ struct dwarf_expr_context
>    /* Frame information used for the evaluation.  */
>    frame_info_ptr m_frame = nullptr;
> 
> +  /* Register cache used for the evaluation, in case there's no frame.  */
> +  reg_buffer *m_regcache = nullptr;
> +
> +  /* gdbarch used for the evaluation.  */
> +  gdbarch *m_gdbarch = nullptr;
> +
>    /* Compilation unit used for the evaluation.  */
>    dwarf2_per_cu_data *m_per_cu = nullptr;
> 
> @@ -258,6 +269,10 @@ struct dwarf_expr_context
>     read as an address in a given FRAME.  */
>  CORE_ADDR read_addr_from_reg (const frame_info_ptr &frame, int reg);
> 
> +/* Return the value of register number REG (a DWARF register number),
> +   read as an address in a given REGCACHE.  */
> +CORE_ADDR read_addr_from_reg (reg_buffer *regcache, int reg);
> +
>  void dwarf_expr_require_composition (const gdb_byte *, const gdb_byte *,
>  				     const char *);
> 
> diff --git a/gdb/dwarf2/frame.c b/gdb/dwarf2/frame.c
> index 841d2d4a2fec..3da9551a7ace 100644
> --- a/gdb/dwarf2/frame.c
> +++ b/gdb/dwarf2/frame.c
> @@ -237,7 +237,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 (exp, len, true, nullptr, this_frame, nullptr);
> 
>    if (result_val->lval () == lval_memory)
>      return result_val->address ();
> diff --git a/gdb/dwarf2/loc.c b/gdb/dwarf2/loc.c
> index d5153862a01d..d7fa58047cdd 100644
> --- a/gdb/dwarf2/loc.c
> +++ b/gdb/dwarf2/loc.c
> @@ -1518,7 +1518,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,
> -			     type, subobj_type, subobj_byte_offset);
> +			     nullptr, type, subobj_type, subobj_byte_offset);
>      }
>    catch (const gdb_exception_error &ex)
>      {
> @@ -1565,11 +1565,12 @@ dwarf2_evaluate_loc_desc (struct type *type,
> const frame_info_ptr &frame,
>  					per_objfile, NULL, 0, as_lval);
>  }
> 
> -/* Evaluates a dwarf expression and stores the result in VAL,
> -   expecting that the dwarf expression only produces a single
> -   CORE_ADDR.  FRAME is the frame in which the expression is
> -   evaluated.  ADDR_STACK is a context (location of a variable) and
> -   might be needed to evaluate the location expression.
> +/* Evaluates a dwarf expression and stores the result in VAL, expecting
> +   that the dwarf expression only produces a single CORE_ADDR.  FRAME is
> +   the frame in which the expression is evaluated.  If FRAME is nullptr,
> +   then registers are read from REGCACHE instead.  ADDR_STACK is a context
> +   (location of a variable) and might be needed to evaluate the location
> +   expression.
> 
>     PUSH_VALUES is an array of values to be pushed to the expression stack
>     before evaluation starts.  PUSH_VALUES[0] is pushed first, then
> @@ -1580,6 +1581,7 @@ dwarf2_evaluate_loc_desc (struct type *type,
> const frame_info_ptr &frame,
>  static int
>  dwarf2_locexpr_baton_eval (const struct dwarf2_locexpr_baton *dlbaton,
>  			   const frame_info_ptr &frame,
> +			   reg_buffer *regcache,
>  			   const struct property_addr_info *addr_stack,
>  			   CORE_ADDR *valp,
>  			   gdb::array_view<CORE_ADDR> push_values,
> @@ -1590,7 +1592,21 @@ dwarf2_locexpr_baton_eval (const struct
> dwarf2_locexpr_baton *dlbaton,
> 
>    dwarf2_per_objfile *per_objfile = dlbaton->per_objfile;
>    dwarf2_per_cu_data *per_cu = dlbaton->per_cu;
> -  dwarf_expr_context ctx (per_objfile, per_cu->addr_size ());
> +  gdbarch *gdbarch;
> +
> +  if (per_objfile != nullptr)
> +    gdbarch = per_objfile->objfile->arch ();
> +  else if (frame != nullptr)
> +    gdbarch = get_frame_arch (frame);
> +  else
> +    {
> +      gdb_assert (regcache != nullptr);
> +      gdbarch = regcache->arch ();
> +    }
> +
> +  int addr_size = (per_cu == nullptr ? gdbarch_addr_bit (gdbarch) / 8
> +		   : per_cu->addr_size ());
> +  dwarf_expr_context ctx (per_objfile, addr_size, gdbarch);
> 
>    value *result;
>    scoped_value_mark free_values;
> @@ -1602,7 +1618,7 @@ dwarf2_locexpr_baton_eval (const struct
> dwarf2_locexpr_baton *dlbaton,
>    try
>      {
>        result = ctx.evaluate (dlbaton->data, dlbaton->size,
> -			     true, per_cu, frame, addr_stack);
> +			     true, per_cu, frame, regcache, addr_stack);
>      }
>    catch (const gdb_exception_error &ex)
>      {
> @@ -1641,6 +1657,7 @@ dwarf2_locexpr_baton_eval (const struct
> dwarf2_locexpr_baton *dlbaton,
>  bool
>  dwarf2_evaluate_property (const dynamic_prop *prop,
>  			  const frame_info_ptr &initial_frame,
> +			  reg_buffer *regcache,
>  			  const property_addr_info *addr_stack,
>  			  CORE_ADDR *value,
>  			  gdb::array_view<CORE_ADDR> push_values)
> @@ -1654,7 +1671,8 @@ dwarf2_evaluate_property (const dynamic_prop
> *prop,
>    scoped_restore_current_language save_language;
>    frame_info_ptr frame = initial_frame;
> 
> -  if (frame == NULL && has_stack_frames ())
> +  /* Only try to get a frame if no regcache was provided.  */
> +  if (frame == nullptr && regcache == nullptr && has_stack_frames ())
>      frame = get_selected_frame (NULL);
> 
>    switch (prop->kind ())
> @@ -1665,8 +1683,9 @@ dwarf2_evaluate_property (const dynamic_prop
> *prop,
>  	gdb_assert (baton->property_type != NULL);
> 
>  	bool is_reference = baton->locexpr.is_reference;
> -	if (dwarf2_locexpr_baton_eval (&baton->locexpr, frame, addr_stack,
> -				       value, push_values, &is_reference))
> +	if (dwarf2_locexpr_baton_eval (&baton->locexpr, frame, regcache,
> +				       addr_stack, value, push_values,
> +				       &is_reference))
>  	  {
>  	    if (is_reference)
>  	      {
> diff --git a/gdb/dwarf2/loc.h b/gdb/dwarf2/loc.h
> index 4fb743618e7c..679c4962d137 100644
> --- a/gdb/dwarf2/loc.h
> +++ b/gdb/dwarf2/loc.h
> @@ -118,8 +118,10 @@ struct property_addr_info
>     etc.  This means the during evaluation PUSH_VALUES[0] will be at the
>     bottom of the stack.  */
> 
> +struct reg_buffer;
>  bool dwarf2_evaluate_property (const struct dynamic_prop *prop,
>  			       const frame_info_ptr &frame,
> +			       reg_buffer *regcache,
>  			       const property_addr_info *addr_stack,
>  			       CORE_ADDR *value,
>  			       gdb::array_view<CORE_ADDR> push_values = {});
> diff --git a/gdb/findvar.c b/gdb/findvar.c
> index f7760aa61ca9..d65bf2fc278c 100644
> --- a/gdb/findvar.c
> +++ b/gdb/findvar.c
> @@ -656,3 +656,20 @@ address_from_register (int regnum, const
> frame_info_ptr &frame)
> 
>    return value_as_address (v.get ());
>  }
> +
> +/* Return contents of register REGNUM in REGCACHE as address.
> +   Will abort if register value is not available.  */
> +
> +CORE_ADDR
> +address_from_register (int regnum, reg_buffer *regcache)
> +{
> +  if (regcache->get_register_status (regnum) != REG_VALID)
> +    throw_error (NOT_AVAILABLE_ERROR, _("register %d is not available"),
> +		 regnum);
> +
> +  gdb_byte buffer[sizeof (CORE_ADDR)];
> +  regcache->raw_collect (regnum, buffer);
> +
> +  type *type = builtin_type (regcache->arch ())->builtin_data_ptr;
> +  return extract_typed_address (buffer, type);
> +}
> diff --git a/gdb/frame.c b/gdb/frame.c
> index 2c1ea012191b..663ff7fa773b 100644
> --- a/gdb/frame.c
> +++ b/gdb/frame.c
> @@ -3175,7 +3175,8 @@ frame_follow_static_link (const frame_info_ptr
> &initial_frame)
> 
>    CORE_ADDR upper_frame_base;
> 
> -  if (!dwarf2_evaluate_property (static_link, initial_frame, NULL,
> &upper_frame_base))
> +  if (!dwarf2_evaluate_property (static_link, initial_frame, nullptr, nullptr,
> +				 &upper_frame_base))
>      return {};
> 
>    /* Now climb up the stack frame until we reach the frame we are interested
> diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
> index 2a3aea229cb0..ea8bad4e826c 100644
> --- a/gdb/gdbtypes.c
> +++ b/gdb/gdbtypes.c
> @@ -2146,7 +2146,7 @@ is_dynamic_type (struct type *type)
> 
>  static struct type *resolve_dynamic_type_internal
>    (struct type *type, struct property_addr_info *addr_stack,
> -   const frame_info_ptr &frame, bool top_level);
> +   const frame_info_ptr &frame, reg_buffer *regcache, bool top_level);
> 
>  /* Given a dynamic range type (dyn_range_type) and a stack of
>     struct property_addr_info elements, return a static version
> @@ -2168,6 +2168,7 @@ static struct type *
>  resolve_dynamic_range (struct type *dyn_range_type,
>  		       struct property_addr_info *addr_stack,
>  		       const frame_info_ptr &frame,
> +		       reg_buffer *regcache,
>  		       int rank, bool resolve_p = true)
>  {
>    CORE_ADDR value;
> @@ -2180,7 +2181,7 @@ resolve_dynamic_range (struct type
> *dyn_range_type,
>    const struct dynamic_prop *prop = &dyn_range_type->bounds ()->low;
>    if (resolve_p)
>      {
> -      if (dwarf2_evaluate_property (prop, frame, addr_stack, &value,
> +      if (dwarf2_evaluate_property (prop, frame, regcache, addr_stack, &value,
>  				    { (CORE_ADDR) rank }))
>  	low_bound.set_const_val (value);
>        else if (prop->kind () == PROP_UNDEFINED)
> @@ -2194,7 +2195,7 @@ resolve_dynamic_range (struct type
> *dyn_range_type,
>    prop = &dyn_range_type->bounds ()->high;
>    if (resolve_p)
>      {
> -      if (dwarf2_evaluate_property (prop, frame, addr_stack, &value,
> +      if (dwarf2_evaluate_property (prop, frame, regcache, addr_stack, &value,
>  				    { (CORE_ADDR) rank }))
>  	{
>  	  high_bound.set_const_val (value);
> @@ -2213,8 +2214,8 @@ resolve_dynamic_range (struct type
> *dyn_range_type,
> 
>    bool byte_stride_p = dyn_range_type->bounds ()->flag_is_byte_stride;
>    prop = &dyn_range_type->bounds ()->stride;
> -  if (resolve_p && dwarf2_evaluate_property (prop, frame, addr_stack,
> &value,
> -					     { (CORE_ADDR) rank }))
> +  if (resolve_p && dwarf2_evaluate_property (prop, frame, regcache,
> addr_stack,
> +					     &value, { (CORE_ADDR) rank }))
>      {
>        stride.set_const_val (value);
> 
> @@ -2236,7 +2237,7 @@ resolve_dynamic_range (struct type
> *dyn_range_type,
> 
>    static_target_type
>      = resolve_dynamic_type_internal (dyn_range_type->target_type (),
> -				     addr_stack, frame, false);
> +				     addr_stack, frame, regcache, false);
>    LONGEST bias = dyn_range_type->bounds ()->bias;
>    type_allocator alloc (dyn_range_type);
>    static_range_type = create_range_type_with_stride
> @@ -2270,6 +2271,7 @@ static struct type *
>  resolve_dynamic_array_or_string_1 (struct type *type,
>  				   struct property_addr_info *addr_stack,
>  				   const frame_info_ptr &frame,
> +				   reg_buffer *regcache,
>  				   int rank, bool resolve_p)
>  {
>    CORE_ADDR value;
> @@ -2299,7 +2301,7 @@ resolve_dynamic_array_or_string_1 (struct type
> *type,
>       dimension of the array.  */
>    prop = TYPE_ALLOCATED_PROP (type);
>    if (prop != NULL && resolve_p
> -      && dwarf2_evaluate_property (prop, frame, addr_stack, &value))
> +      && dwarf2_evaluate_property (prop, frame, regcache, addr_stack,
> &value))
>      {
>        prop->set_const_val (value);
>        if (value == 0)
> @@ -2308,7 +2310,7 @@ resolve_dynamic_array_or_string_1 (struct type
> *type,
> 
>    prop = TYPE_ASSOCIATED_PROP (type);
>    if (prop != NULL && resolve_p
> -      && dwarf2_evaluate_property (prop, frame, addr_stack, &value))
> +      && dwarf2_evaluate_property (prop, frame, regcache, addr_stack,
> &value))
>      {
>        prop->set_const_val (value);
>        if (value == 0)
> @@ -2317,14 +2319,15 @@ resolve_dynamic_array_or_string_1 (struct type
> *type,
> 
>    range_type = check_typedef (type->index_type ());
>    range_type
> -    = resolve_dynamic_range (range_type, addr_stack, frame, rank, resolve_p);
> +    = resolve_dynamic_range (range_type, addr_stack, frame, regcache, rank,
> +			     resolve_p);
> 
>    ary_dim = check_typedef (type->target_type ());
>    if (ary_dim != NULL && ary_dim->code () == TYPE_CODE_ARRAY)
>      {
>        ary_dim = copy_type (ary_dim);
>        elt_type = resolve_dynamic_array_or_string_1 (ary_dim, addr_stack,
> -						    frame, rank - 1,
> +						    frame, regcache, rank - 1,
>  						    resolve_p);
>      }
>    else if (ary_dim != nullptr && ary_dim->code () == TYPE_CODE_STRING)
> @@ -2355,7 +2358,7 @@ resolve_dynamic_array_or_string_1 (struct type
> *type,
>  	 Fortran, and hope that this doesn't cause problems for anyone
>  	 else.  */
>        elt_type = resolve_dynamic_type_internal (type->target_type (),
> -						addr_stack, frame, 0);
> +						addr_stack, frame, regcache,
> 0);
>      }
>    else
>      elt_type = type->target_type ();
> @@ -2365,7 +2368,7 @@ resolve_dynamic_array_or_string_1 (struct type
> *type,
>      prop = nullptr;
>    if (prop != NULL && resolve_p)
>      {
> -      if (dwarf2_evaluate_property (prop, frame, addr_stack, &value))
> +      if (dwarf2_evaluate_property (prop, frame, regcache, addr_stack,
> &value))
>  	{
>  	  type->remove_dyn_prop (DYN_PROP_BYTE_STRIDE);
>  	  bit_stride = (unsigned int) (value * 8);
> @@ -2397,7 +2400,8 @@ resolve_dynamic_array_or_string_1 (struct type
> *type,
>  static struct type *
>  resolve_dynamic_array_or_string (struct type *type,
>  				 struct property_addr_info *addr_stack,
> -				 const frame_info_ptr &frame)
> +				 const frame_info_ptr &frame,
> +				 reg_buffer *regcache)
>  {
>    CORE_ADDR value;
>    int rank = 0;
> @@ -2411,7 +2415,7 @@ resolve_dynamic_array_or_string (struct type
> *type,
> 
>    /* Resolve the rank property to get rank value.  */
>    struct dynamic_prop *prop = TYPE_RANK_PROP (type);
> -  if (dwarf2_evaluate_property (prop, frame, addr_stack, &value))
> +  if (dwarf2_evaluate_property (prop, frame, regcache, addr_stack, &value))
>      {
>        prop->set_const_val (value);
>        rank = value;
> @@ -2479,8 +2483,8 @@ resolve_dynamic_array_or_string (struct type
> *type,
>       reduce the rank by 1 here.  */
>    --rank;
> 
> -  return resolve_dynamic_array_or_string_1 (type, addr_stack, frame, rank,
> -					    true);
> +  return resolve_dynamic_array_or_string_1 (type, addr_stack, frame,
> regcache,
> +					    rank, true);
>  }
> 
>  /* Resolve dynamic bounds of members of the union TYPE to static
> @@ -2490,7 +2494,8 @@ resolve_dynamic_array_or_string (struct type
> *type,
>  static struct type *
>  resolve_dynamic_union (struct type *type,
>  		       struct property_addr_info *addr_stack,
> -		       const frame_info_ptr &frame)
> +		       const frame_info_ptr &frame,
> +		       reg_buffer *regcache)
>  {
>    struct type *resolved_type;
>    int i;
> @@ -2508,7 +2513,7 @@ resolve_dynamic_union (struct type *type,
>  	continue;
> 
>        t = resolve_dynamic_type_internal (resolved_type->field (i).type (),
> -					 addr_stack, frame, false);
> +					 addr_stack, frame, regcache, false);
>        resolved_type->field (i).set_type (t);
> 
>        struct type *real_type = check_typedef (t);
> @@ -2682,7 +2687,8 @@ compute_variant_fields (struct type *type,
>  static struct type *
>  resolve_dynamic_struct (struct type *type,
>  			struct property_addr_info *addr_stack,
> -			const frame_info_ptr &frame)
> +			const frame_info_ptr &frame,
> +			reg_buffer *regcache)
>  {
>    struct type *resolved_type;
>    int i;
> @@ -2725,8 +2731,8 @@ resolve_dynamic_struct (struct type *type,
>  	  prop.set_locexpr (&baton);
> 
>  	  CORE_ADDR addr;
> -	  if (dwarf2_evaluate_property (&prop, frame, addr_stack, &addr,
> -					{addr_stack->addr}))
> +	  if (dwarf2_evaluate_property (&prop, frame, regcache, addr_stack,
> +					&addr, {addr_stack->addr}))
>  	    resolved_type->field (i).set_loc_bitpos
>  	      (TARGET_CHAR_BIT * (addr - addr_stack->addr));
>  	}
> @@ -2752,7 +2758,7 @@ resolve_dynamic_struct (struct type *type,
> 
>        resolved_type->field (i).set_type
>  	(resolve_dynamic_type_internal (resolved_type->field (i).type (),
> -					&pinfo, frame, false));
> +					&pinfo, frame, regcache, false));
>        gdb_assert (resolved_type->field (i).loc_kind ()
>  		  == FIELD_LOC_KIND_BITPOS);
> 
> @@ -2798,6 +2804,7 @@ static struct type *
>  resolve_dynamic_type_internal (struct type *type,
>  			       struct property_addr_info *addr_stack,
>  			       const frame_info_ptr &frame,
> +			       reg_buffer *regcache,
>  			       bool top_level)
>  {
>    struct type *real_type = check_typedef (type);
> @@ -2811,7 +2818,7 @@ resolve_dynamic_type_internal (struct type *type,
>    std::optional<CORE_ADDR> type_length;
>    prop = TYPE_DYNAMIC_LENGTH (type);
>    if (prop != NULL
> -      && dwarf2_evaluate_property (prop, frame, addr_stack, &value))
> +      && dwarf2_evaluate_property (prop, frame, regcache, addr_stack,
> &value))
>      type_length = value;
> 
>    if (type->code () == TYPE_CODE_TYPEDEF)
> @@ -2819,7 +2826,7 @@ resolve_dynamic_type_internal (struct type *type,
>        resolved_type = copy_type (type);
>        resolved_type->set_target_type
>  	(resolve_dynamic_type_internal (type->target_type (), addr_stack,
> -					frame, top_level));
> +					frame, regcache, top_level));
>      }
>    else
>      {
> @@ -2849,8 +2856,8 @@ resolve_dynamic_type_internal (struct type *type,
>  	      {
>  		resolved_type = copy_type (type);
>  		resolved_type->set_target_type
> -		  (resolve_dynamic_type_internal (type->target_type (),
> -						  &pinfo, frame, true));
> +		  (resolve_dynamic_type_internal (type->target_type (),
> &pinfo,
> +						  frame, regcache, true));
>  	      }
>  	    break;
>  	  }
> @@ -2860,7 +2867,7 @@ resolve_dynamic_type_internal (struct type *type,
>  	     treated as one here.  */
>  	case TYPE_CODE_ARRAY:
>  	  resolved_type = resolve_dynamic_array_or_string (type, addr_stack,
> -							   frame);
> +							   frame, regcache);
>  	  break;
> 
>  	case TYPE_CODE_RANGE:
> @@ -2869,15 +2876,18 @@ resolve_dynamic_type_internal (struct type
> *type,
>  	     this rank value is not actually required for the resolution of
>  	     the dynamic range, otherwise, we'd be resolving this range
>  	     within the context of a dynamic array.  */
> -	  resolved_type = resolve_dynamic_range (type, addr_stack, frame, 0);
> +	  resolved_type = resolve_dynamic_range (type, addr_stack, frame,
> +						 regcache, 0);
>  	  break;
> 
>  	case TYPE_CODE_UNION:
> -	  resolved_type = resolve_dynamic_union (type, addr_stack, frame);
> +	  resolved_type = resolve_dynamic_union (type, addr_stack, frame,
> +						 regcache);
>  	  break;
> 
>  	case TYPE_CODE_STRUCT:
> -	  resolved_type = resolve_dynamic_struct (type, addr_stack, frame);
> +	  resolved_type = resolve_dynamic_struct (type, addr_stack, frame,
> +						  regcache);
>  	  break;
>  	}
>      }
> @@ -2894,7 +2904,7 @@ resolve_dynamic_type_internal (struct type *type,
>    /* Resolve data_location attribute.  */
>    prop = TYPE_DATA_LOCATION (resolved_type);
>    if (prop != NULL
> -      && dwarf2_evaluate_property (prop, frame, addr_stack, &value))
> +      && dwarf2_evaluate_property (prop, frame, regcache, addr_stack,
> &value))
>      {
>        /* Start of Fortran hack.  See comment in f-lang.h for what is going
>  	 on here.*/
> @@ -2915,7 +2925,8 @@ struct type *
>  resolve_dynamic_type (struct type *type,
>  		      gdb::array_view<const gdb_byte> valaddr,
>  		      CORE_ADDR addr,
> -		      const frame_info_ptr *in_frame)
> +		      const frame_info_ptr *in_frame,
> +		      reg_buffer *regcache)
>  {
>    struct property_addr_info pinfo
>      = {check_typedef (type), valaddr, addr, NULL};
> @@ -2924,7 +2935,7 @@ resolve_dynamic_type (struct type *type,
>    if (in_frame != nullptr)
>      frame = *in_frame;
> 
> -  return resolve_dynamic_type_internal (type, &pinfo, frame, true);
> +  return resolve_dynamic_type_internal (type, &pinfo, frame, regcache, true);
>  }
> 
>  /* See gdbtypes.h  */
> diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
> index f80bd7e071a3..514af300de3b 100644
> --- a/gdb/gdbtypes.h
> +++ b/gdb/gdbtypes.h
> @@ -2625,9 +2625,12 @@ extern CORE_ADDR get_pointer_type_max
> (struct type *);
>     have a different type when resolved (depending on the contents of
>     memory).  In this situation, 'is_dynamic_type' will still return
>     true for the return value of this function.  */
> +
> +struct reg_buffer;
>  extern struct type *resolve_dynamic_type
>    (struct type *type, gdb::array_view<const gdb_byte> valaddr,
> -   CORE_ADDR addr, const frame_info_ptr *frame = nullptr);
> +   CORE_ADDR addr, const frame_info_ptr *frame = nullptr,
> +   reg_buffer *regcache = nullptr);
> 
>  /* * Predicate if the type has dynamic values, which are not resolved yet.
>     See the caveat in 'resolve_dynamic_type' to understand a scenario
> diff --git a/gdb/gnu-v3-abi.c b/gdb/gnu-v3-abi.c
> index aefbee542703..5cc0d1d2d4f4 100644
> --- a/gdb/gnu-v3-abi.c
> +++ b/gdb/gnu-v3-abi.c
> @@ -493,7 +493,7 @@ gnuv3_baseclass_offset (struct type *type, int index,
>        addr_stack.next = nullptr;
> 
>        CORE_ADDR result;
> -      if (dwarf2_evaluate_property (&prop, nullptr, &addr_stack, &result,
> +      if (dwarf2_evaluate_property (&prop, nullptr, nullptr, &addr_stack,
> &result,
>  				    {addr_stack.addr}))
>  	return (int) (result - addr_stack.addr);
>      }
> diff --git a/gdb/value.h b/gdb/value.h
> index 13cfb007aa2c..802a49066288 100644
> --- a/gdb/value.h
> +++ b/gdb/value.h
> @@ -1133,6 +1133,9 @@ extern struct value *value_from_register (struct
> type *type, int regnum,
> 
>  extern CORE_ADDR address_from_register (int regnum,
>  					const frame_info_ptr &frame);
> +struct reg_buffer;
> +extern CORE_ADDR address_from_register (int regnum,
> +					reg_buffer *regcache);
> 
>  extern struct value *value_of_variable (struct symbol *var,
>  					const struct block *b);

Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
Thiago Jung Bauermann Feb. 15, 2025, 2:55 a.m. UTC | #4
Hello Klaus,

"Gerlicher, Klaus" <klaus.gerlicher@intel.com> writes:

> Given that you are already considering agent expressions, this reply maybe be of limited
> value but I'd still like to point out that DWARF expressions require that the register to
> be evaluated be a DWARF register which is only true for a subset of all registers in an
> architecture. For example, for Intel GPU the register controlling vector length is not a
> DWARF mapped register. Therefore we would have a hard time using this approach.

Indeed, that's a consideration that I didn't face with this patch series
because for SVE (and also SME) registers only the VG register value
needs to be referenced in the expression, which has a DWARF mapping.

That's one more argument in favour of either agent expressions or (as
Christina suggested) a new alternative.

--
Thiago
Gerlicher, Klaus Feb. 17, 2025, 1:02 p.m. UTC | #5
Hi Thiago,

Thanks for the quick response.

> 
> Hello Klaus,
> 
> "Gerlicher, Klaus" <klaus.gerlicher@intel.com> writes:
> 
> > Given that you are already considering agent expressions, this reply maybe
> be of limited
> > value but I'd still like to point out that DWARF expressions require that the
> register to
> > be evaluated be a DWARF register which is only true for a subset of all
> registers in an
> > architecture. For example, for Intel GPU the register controlling vector length
> is not a
> > DWARF mapped register. Therefore we would have a hard time using this
> approach.
> 
> Indeed, that's a consideration that I didn't face with this patch series
> because for SVE (and also SME) registers only the VG register value
> needs to be referenced in the expression, which has a DWARF mapping.
> 
> That's one more argument in favour of either agent expressions or (as
> Christina suggested) a new alternative.

Here's the new alternative (hopefully):

We are wondering if the following approach would be much simpler:
1) in the tdesc, reg definition, just add a "var" attribute to the reg definition.
2) Then in xml-tdesc.c parsing, store in this reg that it's variable. Or a list of GDB regnums for each of the "var" regs.
3) Target dependent in GDB and GDBserver would always know how to determine the size for the such a register. Gdbarch method on GDB side, process_stratum_target method in GDBserver side that you would ask for the size whenever a register is marked as variable. Nothing would need to stored in the target description except this flag. This makes this the most flexible, you don't need any expression evaluator OR rather it's up the the arch to evaluate.
4) of course the early load mechanism could also be dropped if the target dependent code can read a single reg from GDBserver. (Again take this with a grain of salt, maybe I'm missing something.)

Am missing something with the current approach that would make the above impossible?

> 
> --
> Thiago
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
Thiago Jung Bauermann Feb. 19, 2025, 6:16 a.m. UTC | #6
"Gerlicher, Klaus" <klaus.gerlicher@intel.com> writes:

>> "Gerlicher, Klaus" <klaus.gerlicher@intel.com> writes:
>>
>> > Given that you are already considering agent expressions, this reply maybe
>> > be of limited
>> > value but I'd still like to point out that DWARF expressions require that the
>> > register to
>> > be evaluated be a DWARF register which is only true for a subset of all
>> > registers in an
>> > architecture. For example, for Intel GPU the register controlling vector length
>> > is not a
>> > DWARF mapped register. Therefore we would have a hard time using this
>> > approach.
>>
>> Indeed, that's a consideration that I didn't face with this patch series
>> because for SVE (and also SME) registers only the VG register value
>> needs to be referenced in the expression, which has a DWARF mapping.
>>
>> That's one more argument in favour of either agent expressions or (as
>> Christina suggested) a new alternative.
>
> Here's the new alternative (hopefully):
>
> We are wondering if the following approach would be much simpler:
> 1) in the tdesc, reg definition, just add a "var" attribute to the reg definition.
> 2) Then in xml-tdesc.c parsing, store in this reg that it's variable. Or a list of GDB
> regnums for each of the "var" regs.
> 3) Target dependent in GDB and GDBserver would always know how to determine the size for
> the such a register. Gdbarch method on GDB side, process_stratum_target method in
> GDBserver side that you would ask for the size whenever a register is marked as
> variable. Nothing would need to stored in the target description except this flag. This
> makes this the most flexible, you don't need any expression evaluator OR rather it's up
> the the arch to evaluate.
> 4) of course the early load mechanism could also be dropped if the target dependent code
> can read a single reg from GDBserver. (Again take this with a grain of salt, maybe I'm
> missing something.)
>
> Am missing something with the current approach that would make the above impossible?

The "Target Descriptions" section of the GDB manual has this paragraph:

 "To address these problems, the GDB remote protocol allows a target
  system to not only identify itself to GDB, but to actually describe
  its own features. This lets GDB support processor variants it has
  never seen before — to the extent that the descriptions are accurate,
  and that GDB understands them."

My understanding of it is that the more descriptive the target
description is, the better and the less coupling you have between GDB
and gdbserver or another stub (such as QEMU for instance). This patch
series' use of MathML expressions allows the target description to fully
describe how the register size is calculated.

In contrast, number 3 above essentially says that GDB and gdbserver
would both have to know and agree on how to determine the size of a
variable size register, and each would do so on its own. In other words,
there would be a tight coupling between GDB and gdbserver (or QEMU or
another stub) and the target description wouldn't be very descriptive.
I think that's a disadvantage of the proposed approach.

I have three slightly different alternative suggestions that would
actually allow your approach without removing the expressiveness that
I rely on for SVE and SME:

1. You could define a new register that would contain the value that
gdbserver needs to pass to GDB so that the latter can calculate the
register size using it in an expression; or

2. since MathML allows defining variables referenced by name, you could
define one that has the value GDB needs to use to determine the register
size using it in an expression; or

3. since MathML allows applying a function referenced by its name, you
could define one that does the computation you need to determine the
register size using it in an expression.

Actually, they are all essentially the same proposal except that one
uses a register and the others use MathML symbols.

What do you think?

--
Thiago
Gerlicher, Klaus March 12, 2025, 4 p.m. UTC | #7
Hi Thiago,

See inline please.

> -----Original Message-----
> From: Thiago Jung Bauermann <thiago.bauermann@linaro.org>
> Sent: Wednesday, February 19, 2025 7:17 AM
> To: Gerlicher, Klaus <klaus.gerlicher@intel.com>
> Cc: gdb-patches@sourceware.org
> Subject: Re: [RFC PATCH v4 08/15] GDB: Allow DWARF expression evaluation
> to use regcache
> 
> "Gerlicher, Klaus" <klaus.gerlicher@intel.com> writes:
> 
> >> "Gerlicher, Klaus" <klaus.gerlicher@intel.com> writes:
> >>
> >> > Given that you are already considering agent expressions, this reply
> maybe
> >> > be of limited
> >> > value but I'd still like to point out that DWARF expressions require that the
> >> > register to
> >> > be evaluated be a DWARF register which is only true for a subset of all
> >> > registers in an
> >> > architecture. For example, for Intel GPU the register controlling vector
> length
> >> > is not a
> >> > DWARF mapped register. Therefore we would have a hard time using this
> >> > approach.
> >>
> >> Indeed, that's a consideration that I didn't face with this patch series
> >> because for SVE (and also SME) registers only the VG register value
> >> needs to be referenced in the expression, which has a DWARF mapping.
> >>
> >> That's one more argument in favour of either agent expressions or (as
> >> Christina suggested) a new alternative.
> >
> > Here's the new alternative (hopefully):
> >
> > We are wondering if the following approach would be much simpler:
> > 1) in the tdesc, reg definition, just add a "var" attribute to the reg definition.
> > 2) Then in xml-tdesc.c parsing, store in this reg that it's variable. Or a list of
> GDB
> > regnums for each of the "var" regs.
> > 3) Target dependent in GDB and GDBserver would always know how to
> determine the size for
> > the such a register. Gdbarch method on GDB side, process_stratum_target
> method in
> > GDBserver side that you would ask for the size whenever a register is marked
> as
> > variable. Nothing would need to stored in the target description except this
> flag. This
> > makes this the most flexible, you don't need any expression evaluator OR
> rather it's up
> > the the arch to evaluate.
> > 4) of course the early load mechanism could also be dropped if the target
> dependent code
> > can read a single reg from GDBserver. (Again take this with a grain of salt,
> maybe I'm
> > missing something.)
> >
> > Am missing something with the current approach that would make the
> above impossible?
> 
> The "Target Descriptions" section of the GDB manual has this paragraph:
> 
>  "To address these problems, the GDB remote protocol allows a target
>   system to not only identify itself to GDB, but to actually describe
>   its own features. This lets GDB support processor variants it has
>   never seen before — to the extent that the descriptions are accurate,
>   and that GDB understands them."
> 
> My understanding of it is that the more descriptive the target
> description is, the better and the less coupling you have between GDB
> and gdbserver or another stub (such as QEMU for instance). This patch
> series' use of MathML expressions allows the target description to fully
> describe how the register size is calculated.
> 

We discussed this internally and your assessment is right, we can't rely on 
strong coupling between GDB and GDBserver here.

However, since you mention this, you are changing the XML, so I would assume 
that this will also break backward compatibility with older GDBs. Parsing 
the XML would likely fail for and older GDB because it won't know about the new
elements. To avoid this, have you given thought to solving this with a 
qSupported packet?

> In contrast, number 3 above essentially says that GDB and gdbserver
> would both have to know and agree on how to determine the size of a
> variable size register, and each would do so on its own. In other words,
> there would be a tight coupling between GDB and gdbserver (or QEMU or
> another stub) and the target description wouldn't be very descriptive.
> I think that's a disadvantage of the proposed approach.
> 
> I have three slightly different alternative suggestions that would
> actually allow your approach without removing the expressiveness that
> I rely on for SVE and SME:
> 
> 1. You could define a new register that would contain the value that
> gdbserver needs to pass to GDB so that the latter can calculate the
> register size using it in an expression; or
> 
> 2. since MathML allows defining variables referenced by name, you could
> define one that has the value GDB needs to use to determine the register
> size using it in an expression; or
> 
> 3. since MathML allows applying a function referenced by its name, you
> could define one that does the computation you need to determine the
> register size using it in an expression.
> 
> Actually, they are all essentially the same proposal except that one
> uses a register and the others use MathML symbols.
> 
> What do you think?

I agree we could extend your mechanism but we would have to explore this a little further.

We are actually preparing another proposal for solving this and the dynamic register count we need
for our implementations. We will post this proposal within the next few days hopefully.

Thanks for your effort
Klaus

> 
> --
> Thiago
Intel Deutschland GmbH
Registered Address: Am Campeon 10, 85579 Neubiberg, Germany
Tel: +49 89 99 8853-0, www.intel.de
Managing Directors: Sean Fennelly, Jeffrey Schneiderman, Tiffany Doon Silva
Chairperson of the Supervisory Board: Nicole Lau
Registered Office: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
diff mbox series

Patch

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index 5ad17eaaaff8..4a667dbd8107 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -56,6 +56,20 @@  ensure_have_frame (const frame_info_ptr &frame, const char *op_name)
 		 _("%s evaluation requires a frame."), op_name);
 }
 
+/* Ensure that either a FRAME or a REGCACHE is defined, throw an exception
+   otherwise.  */
+
+static void
+ensure_have_frame_or_regcache (const frame_info_ptr &frame,
+			       const reg_buffer *regcache,
+			       const char *op_name)
+{
+  if (frame == nullptr && regcache == nullptr)
+    throw_error (GENERIC_ERROR,
+		 _("%s evaluation requires a frame or register cache."),
+		 op_name);
+}
+
 /* Ensure that a PER_CU is defined and throw an exception otherwise.  */
 
 static void
@@ -86,6 +100,16 @@  read_addr_from_reg (const frame_info_ptr &frame, int reg)
   return address_from_register (regnum, frame);
 }
 
+/* See expr.h.  */
+
+CORE_ADDR
+read_addr_from_reg (reg_buffer *regcache, int reg)
+{
+  int regnum = dwarf_reg_to_regnum_or_error (regcache->arch (), reg);
+
+  return address_from_register (regnum, regcache);
+}
+
 struct piece_closure
 {
   /* Reference count.  */
@@ -690,7 +714,8 @@  sect_variable_value (sect_offset sect_off,
 struct type *
 dwarf_expr_context::address_type () const
 {
-  gdbarch *arch = this->m_per_objfile->objfile->arch ();
+  gdbarch *arch = (m_gdbarch == nullptr ? this->m_per_objfile->objfile->arch ()
+		   : m_gdbarch);
   dwarf_gdbarch_types *types = dwarf_arch_cookie.get (arch);
   if (types == nullptr)
     types = dwarf_arch_cookie.emplace (arch);
@@ -720,9 +745,11 @@  dwarf_expr_context::address_type () const
 /* Create a new context for the expression evaluator.  */
 
 dwarf_expr_context::dwarf_expr_context (dwarf2_per_objfile *per_objfile,
-					int addr_size)
+					int addr_size,
+					gdbarch *gdbarch)
 : m_addr_size (addr_size),
-  m_per_objfile (per_objfile)
+  m_per_objfile (per_objfile),
+  m_gdbarch (gdbarch)
 {
 }
 
@@ -915,7 +942,6 @@  dwarf_expr_context::fetch_result (struct type *type, struct type *subobj_type,
 				  LONGEST subobj_offset, bool as_lval)
 {
   value *retval = nullptr;
-  gdbarch *arch = this->m_per_objfile->objfile->arch ();
 
   if (type == nullptr)
     type = address_type ();
@@ -948,6 +974,9 @@  dwarf_expr_context::fetch_result (struct type *type, struct type *subobj_type,
     }
   else
     {
+      gdbarch *arch = (m_gdbarch == nullptr ? this->m_per_objfile->objfile->arch ()
+		       : m_gdbarch);
+
       /* If AS_LVAL is false, means that the implicit conversion
 	 from a location description to value is expected.  */
       if (!as_lval)
@@ -1077,12 +1106,14 @@  dwarf_expr_context::fetch_result (struct type *type, struct type *subobj_type,
 value *
 dwarf_expr_context::evaluate (const gdb_byte *addr, size_t len, bool as_lval,
 			      dwarf2_per_cu_data *per_cu, const frame_info_ptr &frame,
+			      reg_buffer *regcache,
 			      const struct property_addr_info *addr_info,
 			      struct type *type, struct type *subobj_type,
 			      LONGEST subobj_offset)
 {
   this->m_per_cu = per_cu;
   this->m_frame = frame;
+  this->m_regcache = regcache;
   this->m_addr_info = addr_info;
 
   eval (addr, len);
@@ -1149,7 +1180,8 @@  get_signed_type (struct gdbarch *gdbarch, struct type *type)
 CORE_ADDR
 dwarf_expr_context::fetch_address (int n)
 {
-  gdbarch *arch = this->m_per_objfile->objfile->arch ();
+  gdbarch *arch = (m_gdbarch == nullptr ? this->m_per_objfile->objfile->arch ()
+		   : m_gdbarch);
   value *result_val = fetch (n);
   bfd_endian byte_order = gdbarch_byte_order (arch);
   ULONGEST result;
@@ -1493,7 +1525,8 @@  void
 dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 				      const gdb_byte *op_end)
 {
-  gdbarch *arch = this->m_per_objfile->objfile->arch ();
+  gdbarch *arch = (this->m_gdbarch ? this->m_gdbarch
+		   : this->m_per_objfile->objfile->arch ());
   bfd_endian byte_order = gdbarch_byte_order (arch);
   /* Old-style "untyped" DWARF values need special treatment in a
      couple of places, specifically DW_OP_mod and DW_OP_shr.  We need
@@ -1784,9 +1817,14 @@  dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 	case DW_OP_breg31:
 	  {
 	    op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
-	    ensure_have_frame (this->m_frame, "DW_OP_breg");
+	    ensure_have_frame_or_regcache (this->m_frame, this->m_regcache,
+					   "DW_OP_breg");
+
+	    if (this->m_frame != nullptr)
+	      result = read_addr_from_reg (this->m_frame, op - DW_OP_breg0);
+	    else
+	      result = read_addr_from_reg (this->m_regcache, op - DW_OP_breg0);
 
-	    result = read_addr_from_reg (this->m_frame, op - DW_OP_breg0);
 	    result += offset;
 	    result_val = value_from_ulongest (address_type, result);
 	  }
@@ -1795,9 +1833,14 @@  dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 	  {
 	    op_ptr = safe_read_uleb128 (op_ptr, op_end, &reg);
 	    op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
-	    ensure_have_frame (this->m_frame, "DW_OP_bregx");
+	    ensure_have_frame_or_regcache (this->m_frame, this->m_regcache,
+					   "DW_OP_bregx");
+
+	    if (this->m_frame != nullptr)
+	      result = read_addr_from_reg (this->m_frame, reg);
+	    else
+	      result = read_addr_from_reg (this->m_regcache, reg);
 
-	    result = read_addr_from_reg (this->m_frame, reg);
 	    result += offset;
 	    result_val = value_from_ulongest (address_type, result);
 	  }
diff --git a/gdb/dwarf2/expr.h b/gdb/dwarf2/expr.h
index b02cc5316406..9a3c92650664 100644
--- a/gdb/dwarf2/expr.h
+++ b/gdb/dwarf2/expr.h
@@ -115,12 +115,14 @@  struct dwarf_stack_value
   bool in_stack_memory;
 };
 
+struct reg_buffer;
+
 /* The expression evaluator works with a dwarf_expr_context, describing
    its current state and its callbacks.  */
 struct dwarf_expr_context
 {
   dwarf_expr_context (dwarf2_per_objfile *per_objfile,
-		      int addr_size);
+		      int addr_size, gdbarch *gdbarch = nullptr);
   virtual ~dwarf_expr_context () = default;
 
   void push_address (CORE_ADDR value, bool in_stack_memory);
@@ -128,6 +130,8 @@  struct dwarf_expr_context
   /* Evaluate the expression at ADDR (LEN bytes long) in a given PER_CU
      and FRAME context.
 
+     If FRAME is nullptr, then registers are read from REGCACHE.
+
      AS_LVAL defines if the returned struct value is expected to be a
      value (false) or a location description (true).
 
@@ -138,6 +142,7 @@  struct dwarf_expr_context
      memory addresses with the passed in buffer.  */
   value *evaluate (const gdb_byte *addr, size_t len, bool as_lval,
 		   dwarf2_per_cu_data *per_cu, const frame_info_ptr &frame,
+		   reg_buffer *regcache,
 		   const struct property_addr_info *addr_info = nullptr,
 		   struct type *type = nullptr,
 		   struct type *subobj_type = nullptr,
@@ -198,6 +203,12 @@  struct dwarf_expr_context
   /* Frame information used for the evaluation.  */
   frame_info_ptr m_frame = nullptr;
 
+  /* Register cache used for the evaluation, in case there's no frame.  */
+  reg_buffer *m_regcache = nullptr;
+
+  /* gdbarch used for the evaluation.  */
+  gdbarch *m_gdbarch = nullptr;
+
   /* Compilation unit used for the evaluation.  */
   dwarf2_per_cu_data *m_per_cu = nullptr;
 
@@ -258,6 +269,10 @@  struct dwarf_expr_context
    read as an address in a given FRAME.  */
 CORE_ADDR read_addr_from_reg (const frame_info_ptr &frame, int reg);
 
+/* Return the value of register number REG (a DWARF register number),
+   read as an address in a given REGCACHE.  */
+CORE_ADDR read_addr_from_reg (reg_buffer *regcache, int reg);
+
 void dwarf_expr_require_composition (const gdb_byte *, const gdb_byte *,
 				     const char *);
 
diff --git a/gdb/dwarf2/frame.c b/gdb/dwarf2/frame.c
index 841d2d4a2fec..3da9551a7ace 100644
--- a/gdb/dwarf2/frame.c
+++ b/gdb/dwarf2/frame.c
@@ -237,7 +237,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 (exp, len, true, nullptr, this_frame, nullptr);
 
   if (result_val->lval () == lval_memory)
     return result_val->address ();
diff --git a/gdb/dwarf2/loc.c b/gdb/dwarf2/loc.c
index d5153862a01d..d7fa58047cdd 100644
--- a/gdb/dwarf2/loc.c
+++ b/gdb/dwarf2/loc.c
@@ -1518,7 +1518,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,
-			     type, subobj_type, subobj_byte_offset);
+			     nullptr, type, subobj_type, subobj_byte_offset);
     }
   catch (const gdb_exception_error &ex)
     {
@@ -1565,11 +1565,12 @@  dwarf2_evaluate_loc_desc (struct type *type, const frame_info_ptr &frame,
 					per_objfile, NULL, 0, as_lval);
 }
 
-/* Evaluates a dwarf expression and stores the result in VAL,
-   expecting that the dwarf expression only produces a single
-   CORE_ADDR.  FRAME is the frame in which the expression is
-   evaluated.  ADDR_STACK is a context (location of a variable) and
-   might be needed to evaluate the location expression.
+/* Evaluates a dwarf expression and stores the result in VAL, expecting
+   that the dwarf expression only produces a single CORE_ADDR.  FRAME is
+   the frame in which the expression is evaluated.  If FRAME is nullptr,
+   then registers are read from REGCACHE instead.  ADDR_STACK is a context
+   (location of a variable) and might be needed to evaluate the location
+   expression.
 
    PUSH_VALUES is an array of values to be pushed to the expression stack
    before evaluation starts.  PUSH_VALUES[0] is pushed first, then
@@ -1580,6 +1581,7 @@  dwarf2_evaluate_loc_desc (struct type *type, const frame_info_ptr &frame,
 static int
 dwarf2_locexpr_baton_eval (const struct dwarf2_locexpr_baton *dlbaton,
 			   const frame_info_ptr &frame,
+			   reg_buffer *regcache,
 			   const struct property_addr_info *addr_stack,
 			   CORE_ADDR *valp,
 			   gdb::array_view<CORE_ADDR> push_values,
@@ -1590,7 +1592,21 @@  dwarf2_locexpr_baton_eval (const struct dwarf2_locexpr_baton *dlbaton,
 
   dwarf2_per_objfile *per_objfile = dlbaton->per_objfile;
   dwarf2_per_cu_data *per_cu = dlbaton->per_cu;
-  dwarf_expr_context ctx (per_objfile, per_cu->addr_size ());
+  gdbarch *gdbarch;
+
+  if (per_objfile != nullptr)
+    gdbarch = per_objfile->objfile->arch ();
+  else if (frame != nullptr)
+    gdbarch = get_frame_arch (frame);
+  else
+    {
+      gdb_assert (regcache != nullptr);
+      gdbarch = regcache->arch ();
+    }
+
+  int addr_size = (per_cu == nullptr ? gdbarch_addr_bit (gdbarch) / 8
+		   : per_cu->addr_size ());
+  dwarf_expr_context ctx (per_objfile, addr_size, gdbarch);
 
   value *result;
   scoped_value_mark free_values;
@@ -1602,7 +1618,7 @@  dwarf2_locexpr_baton_eval (const struct dwarf2_locexpr_baton *dlbaton,
   try
     {
       result = ctx.evaluate (dlbaton->data, dlbaton->size,
-			     true, per_cu, frame, addr_stack);
+			     true, per_cu, frame, regcache, addr_stack);
     }
   catch (const gdb_exception_error &ex)
     {
@@ -1641,6 +1657,7 @@  dwarf2_locexpr_baton_eval (const struct dwarf2_locexpr_baton *dlbaton,
 bool
 dwarf2_evaluate_property (const dynamic_prop *prop,
 			  const frame_info_ptr &initial_frame,
+			  reg_buffer *regcache,
 			  const property_addr_info *addr_stack,
 			  CORE_ADDR *value,
 			  gdb::array_view<CORE_ADDR> push_values)
@@ -1654,7 +1671,8 @@  dwarf2_evaluate_property (const dynamic_prop *prop,
   scoped_restore_current_language save_language;
   frame_info_ptr frame = initial_frame;
 
-  if (frame == NULL && has_stack_frames ())
+  /* Only try to get a frame if no regcache was provided.  */
+  if (frame == nullptr && regcache == nullptr && has_stack_frames ())
     frame = get_selected_frame (NULL);
 
   switch (prop->kind ())
@@ -1665,8 +1683,9 @@  dwarf2_evaluate_property (const dynamic_prop *prop,
 	gdb_assert (baton->property_type != NULL);
 
 	bool is_reference = baton->locexpr.is_reference;
-	if (dwarf2_locexpr_baton_eval (&baton->locexpr, frame, addr_stack,
-				       value, push_values, &is_reference))
+	if (dwarf2_locexpr_baton_eval (&baton->locexpr, frame, regcache,
+				       addr_stack, value, push_values,
+				       &is_reference))
 	  {
 	    if (is_reference)
 	      {
diff --git a/gdb/dwarf2/loc.h b/gdb/dwarf2/loc.h
index 4fb743618e7c..679c4962d137 100644
--- a/gdb/dwarf2/loc.h
+++ b/gdb/dwarf2/loc.h
@@ -118,8 +118,10 @@  struct property_addr_info
    etc.  This means the during evaluation PUSH_VALUES[0] will be at the
    bottom of the stack.  */
 
+struct reg_buffer;
 bool dwarf2_evaluate_property (const struct dynamic_prop *prop,
 			       const frame_info_ptr &frame,
+			       reg_buffer *regcache,
 			       const property_addr_info *addr_stack,
 			       CORE_ADDR *value,
 			       gdb::array_view<CORE_ADDR> push_values = {});
diff --git a/gdb/findvar.c b/gdb/findvar.c
index f7760aa61ca9..d65bf2fc278c 100644
--- a/gdb/findvar.c
+++ b/gdb/findvar.c
@@ -656,3 +656,20 @@  address_from_register (int regnum, const frame_info_ptr &frame)
 
   return value_as_address (v.get ());
 }
+
+/* Return contents of register REGNUM in REGCACHE as address.
+   Will abort if register value is not available.  */
+
+CORE_ADDR
+address_from_register (int regnum, reg_buffer *regcache)
+{
+  if (regcache->get_register_status (regnum) != REG_VALID)
+    throw_error (NOT_AVAILABLE_ERROR, _("register %d is not available"),
+		 regnum);
+
+  gdb_byte buffer[sizeof (CORE_ADDR)];
+  regcache->raw_collect (regnum, buffer);
+
+  type *type = builtin_type (regcache->arch ())->builtin_data_ptr;
+  return extract_typed_address (buffer, type);
+}
diff --git a/gdb/frame.c b/gdb/frame.c
index 2c1ea012191b..663ff7fa773b 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -3175,7 +3175,8 @@  frame_follow_static_link (const frame_info_ptr &initial_frame)
 
   CORE_ADDR upper_frame_base;
 
-  if (!dwarf2_evaluate_property (static_link, initial_frame, NULL, &upper_frame_base))
+  if (!dwarf2_evaluate_property (static_link, initial_frame, nullptr, nullptr,
+				 &upper_frame_base))
     return {};
 
   /* Now climb up the stack frame until we reach the frame we are interested
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 2a3aea229cb0..ea8bad4e826c 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -2146,7 +2146,7 @@  is_dynamic_type (struct type *type)
 
 static struct type *resolve_dynamic_type_internal
   (struct type *type, struct property_addr_info *addr_stack,
-   const frame_info_ptr &frame, bool top_level);
+   const frame_info_ptr &frame, reg_buffer *regcache, bool top_level);
 
 /* Given a dynamic range type (dyn_range_type) and a stack of
    struct property_addr_info elements, return a static version
@@ -2168,6 +2168,7 @@  static struct type *
 resolve_dynamic_range (struct type *dyn_range_type,
 		       struct property_addr_info *addr_stack,
 		       const frame_info_ptr &frame,
+		       reg_buffer *regcache,
 		       int rank, bool resolve_p = true)
 {
   CORE_ADDR value;
@@ -2180,7 +2181,7 @@  resolve_dynamic_range (struct type *dyn_range_type,
   const struct dynamic_prop *prop = &dyn_range_type->bounds ()->low;
   if (resolve_p)
     {
-      if (dwarf2_evaluate_property (prop, frame, addr_stack, &value,
+      if (dwarf2_evaluate_property (prop, frame, regcache, addr_stack, &value,
 				    { (CORE_ADDR) rank }))
 	low_bound.set_const_val (value);
       else if (prop->kind () == PROP_UNDEFINED)
@@ -2194,7 +2195,7 @@  resolve_dynamic_range (struct type *dyn_range_type,
   prop = &dyn_range_type->bounds ()->high;
   if (resolve_p)
     {
-      if (dwarf2_evaluate_property (prop, frame, addr_stack, &value,
+      if (dwarf2_evaluate_property (prop, frame, regcache, addr_stack, &value,
 				    { (CORE_ADDR) rank }))
 	{
 	  high_bound.set_const_val (value);
@@ -2213,8 +2214,8 @@  resolve_dynamic_range (struct type *dyn_range_type,
 
   bool byte_stride_p = dyn_range_type->bounds ()->flag_is_byte_stride;
   prop = &dyn_range_type->bounds ()->stride;
-  if (resolve_p && dwarf2_evaluate_property (prop, frame, addr_stack, &value,
-					     { (CORE_ADDR) rank }))
+  if (resolve_p && dwarf2_evaluate_property (prop, frame, regcache, addr_stack,
+					     &value, { (CORE_ADDR) rank }))
     {
       stride.set_const_val (value);
 
@@ -2236,7 +2237,7 @@  resolve_dynamic_range (struct type *dyn_range_type,
 
   static_target_type
     = resolve_dynamic_type_internal (dyn_range_type->target_type (),
-				     addr_stack, frame, false);
+				     addr_stack, frame, regcache, false);
   LONGEST bias = dyn_range_type->bounds ()->bias;
   type_allocator alloc (dyn_range_type);
   static_range_type = create_range_type_with_stride
@@ -2270,6 +2271,7 @@  static struct type *
 resolve_dynamic_array_or_string_1 (struct type *type,
 				   struct property_addr_info *addr_stack,
 				   const frame_info_ptr &frame,
+				   reg_buffer *regcache,
 				   int rank, bool resolve_p)
 {
   CORE_ADDR value;
@@ -2299,7 +2301,7 @@  resolve_dynamic_array_or_string_1 (struct type *type,
      dimension of the array.  */
   prop = TYPE_ALLOCATED_PROP (type);
   if (prop != NULL && resolve_p
-      && dwarf2_evaluate_property (prop, frame, addr_stack, &value))
+      && dwarf2_evaluate_property (prop, frame, regcache, addr_stack, &value))
     {
       prop->set_const_val (value);
       if (value == 0)
@@ -2308,7 +2310,7 @@  resolve_dynamic_array_or_string_1 (struct type *type,
 
   prop = TYPE_ASSOCIATED_PROP (type);
   if (prop != NULL && resolve_p
-      && dwarf2_evaluate_property (prop, frame, addr_stack, &value))
+      && dwarf2_evaluate_property (prop, frame, regcache, addr_stack, &value))
     {
       prop->set_const_val (value);
       if (value == 0)
@@ -2317,14 +2319,15 @@  resolve_dynamic_array_or_string_1 (struct type *type,
 
   range_type = check_typedef (type->index_type ());
   range_type
-    = resolve_dynamic_range (range_type, addr_stack, frame, rank, resolve_p);
+    = resolve_dynamic_range (range_type, addr_stack, frame, regcache, rank,
+			     resolve_p);
 
   ary_dim = check_typedef (type->target_type ());
   if (ary_dim != NULL && ary_dim->code () == TYPE_CODE_ARRAY)
     {
       ary_dim = copy_type (ary_dim);
       elt_type = resolve_dynamic_array_or_string_1 (ary_dim, addr_stack,
-						    frame, rank - 1,
+						    frame, regcache, rank - 1,
 						    resolve_p);
     }
   else if (ary_dim != nullptr && ary_dim->code () == TYPE_CODE_STRING)
@@ -2355,7 +2358,7 @@  resolve_dynamic_array_or_string_1 (struct type *type,
 	 Fortran, and hope that this doesn't cause problems for anyone
 	 else.  */
       elt_type = resolve_dynamic_type_internal (type->target_type (),
-						addr_stack, frame, 0);
+						addr_stack, frame, regcache, 0);
     }
   else
     elt_type = type->target_type ();
@@ -2365,7 +2368,7 @@  resolve_dynamic_array_or_string_1 (struct type *type,
     prop = nullptr;
   if (prop != NULL && resolve_p)
     {
-      if (dwarf2_evaluate_property (prop, frame, addr_stack, &value))
+      if (dwarf2_evaluate_property (prop, frame, regcache, addr_stack, &value))
 	{
 	  type->remove_dyn_prop (DYN_PROP_BYTE_STRIDE);
 	  bit_stride = (unsigned int) (value * 8);
@@ -2397,7 +2400,8 @@  resolve_dynamic_array_or_string_1 (struct type *type,
 static struct type *
 resolve_dynamic_array_or_string (struct type *type,
 				 struct property_addr_info *addr_stack,
-				 const frame_info_ptr &frame)
+				 const frame_info_ptr &frame,
+				 reg_buffer *regcache)
 {
   CORE_ADDR value;
   int rank = 0;
@@ -2411,7 +2415,7 @@  resolve_dynamic_array_or_string (struct type *type,
 
   /* Resolve the rank property to get rank value.  */
   struct dynamic_prop *prop = TYPE_RANK_PROP (type);
-  if (dwarf2_evaluate_property (prop, frame, addr_stack, &value))
+  if (dwarf2_evaluate_property (prop, frame, regcache, addr_stack, &value))
     {
       prop->set_const_val (value);
       rank = value;
@@ -2479,8 +2483,8 @@  resolve_dynamic_array_or_string (struct type *type,
      reduce the rank by 1 here.  */
   --rank;
 
-  return resolve_dynamic_array_or_string_1 (type, addr_stack, frame, rank,
-					    true);
+  return resolve_dynamic_array_or_string_1 (type, addr_stack, frame, regcache,
+					    rank, true);
 }
 
 /* Resolve dynamic bounds of members of the union TYPE to static
@@ -2490,7 +2494,8 @@  resolve_dynamic_array_or_string (struct type *type,
 static struct type *
 resolve_dynamic_union (struct type *type,
 		       struct property_addr_info *addr_stack,
-		       const frame_info_ptr &frame)
+		       const frame_info_ptr &frame,
+		       reg_buffer *regcache)
 {
   struct type *resolved_type;
   int i;
@@ -2508,7 +2513,7 @@  resolve_dynamic_union (struct type *type,
 	continue;
 
       t = resolve_dynamic_type_internal (resolved_type->field (i).type (),
-					 addr_stack, frame, false);
+					 addr_stack, frame, regcache, false);
       resolved_type->field (i).set_type (t);
 
       struct type *real_type = check_typedef (t);
@@ -2682,7 +2687,8 @@  compute_variant_fields (struct type *type,
 static struct type *
 resolve_dynamic_struct (struct type *type,
 			struct property_addr_info *addr_stack,
-			const frame_info_ptr &frame)
+			const frame_info_ptr &frame,
+			reg_buffer *regcache)
 {
   struct type *resolved_type;
   int i;
@@ -2725,8 +2731,8 @@  resolve_dynamic_struct (struct type *type,
 	  prop.set_locexpr (&baton);
 
 	  CORE_ADDR addr;
-	  if (dwarf2_evaluate_property (&prop, frame, addr_stack, &addr,
-					{addr_stack->addr}))
+	  if (dwarf2_evaluate_property (&prop, frame, regcache, addr_stack,
+					&addr, {addr_stack->addr}))
 	    resolved_type->field (i).set_loc_bitpos
 	      (TARGET_CHAR_BIT * (addr - addr_stack->addr));
 	}
@@ -2752,7 +2758,7 @@  resolve_dynamic_struct (struct type *type,
 
       resolved_type->field (i).set_type
 	(resolve_dynamic_type_internal (resolved_type->field (i).type (),
-					&pinfo, frame, false));
+					&pinfo, frame, regcache, false));
       gdb_assert (resolved_type->field (i).loc_kind ()
 		  == FIELD_LOC_KIND_BITPOS);
 
@@ -2798,6 +2804,7 @@  static struct type *
 resolve_dynamic_type_internal (struct type *type,
 			       struct property_addr_info *addr_stack,
 			       const frame_info_ptr &frame,
+			       reg_buffer *regcache,
 			       bool top_level)
 {
   struct type *real_type = check_typedef (type);
@@ -2811,7 +2818,7 @@  resolve_dynamic_type_internal (struct type *type,
   std::optional<CORE_ADDR> type_length;
   prop = TYPE_DYNAMIC_LENGTH (type);
   if (prop != NULL
-      && dwarf2_evaluate_property (prop, frame, addr_stack, &value))
+      && dwarf2_evaluate_property (prop, frame, regcache, addr_stack, &value))
     type_length = value;
 
   if (type->code () == TYPE_CODE_TYPEDEF)
@@ -2819,7 +2826,7 @@  resolve_dynamic_type_internal (struct type *type,
       resolved_type = copy_type (type);
       resolved_type->set_target_type
 	(resolve_dynamic_type_internal (type->target_type (), addr_stack,
-					frame, top_level));
+					frame, regcache, top_level));
     }
   else
     {
@@ -2849,8 +2856,8 @@  resolve_dynamic_type_internal (struct type *type,
 	      {
 		resolved_type = copy_type (type);
 		resolved_type->set_target_type
-		  (resolve_dynamic_type_internal (type->target_type (),
-						  &pinfo, frame, true));
+		  (resolve_dynamic_type_internal (type->target_type (), &pinfo,
+						  frame, regcache, true));
 	      }
 	    break;
 	  }
@@ -2860,7 +2867,7 @@  resolve_dynamic_type_internal (struct type *type,
 	     treated as one here.  */
 	case TYPE_CODE_ARRAY:
 	  resolved_type = resolve_dynamic_array_or_string (type, addr_stack,
-							   frame);
+							   frame, regcache);
 	  break;
 
 	case TYPE_CODE_RANGE:
@@ -2869,15 +2876,18 @@  resolve_dynamic_type_internal (struct type *type,
 	     this rank value is not actually required for the resolution of
 	     the dynamic range, otherwise, we'd be resolving this range
 	     within the context of a dynamic array.  */
-	  resolved_type = resolve_dynamic_range (type, addr_stack, frame, 0);
+	  resolved_type = resolve_dynamic_range (type, addr_stack, frame,
+						 regcache, 0);
 	  break;
 
 	case TYPE_CODE_UNION:
-	  resolved_type = resolve_dynamic_union (type, addr_stack, frame);
+	  resolved_type = resolve_dynamic_union (type, addr_stack, frame,
+						 regcache);
 	  break;
 
 	case TYPE_CODE_STRUCT:
-	  resolved_type = resolve_dynamic_struct (type, addr_stack, frame);
+	  resolved_type = resolve_dynamic_struct (type, addr_stack, frame,
+						  regcache);
 	  break;
 	}
     }
@@ -2894,7 +2904,7 @@  resolve_dynamic_type_internal (struct type *type,
   /* Resolve data_location attribute.  */
   prop = TYPE_DATA_LOCATION (resolved_type);
   if (prop != NULL
-      && dwarf2_evaluate_property (prop, frame, addr_stack, &value))
+      && dwarf2_evaluate_property (prop, frame, regcache, addr_stack, &value))
     {
       /* Start of Fortran hack.  See comment in f-lang.h for what is going
 	 on here.*/
@@ -2915,7 +2925,8 @@  struct type *
 resolve_dynamic_type (struct type *type,
 		      gdb::array_view<const gdb_byte> valaddr,
 		      CORE_ADDR addr,
-		      const frame_info_ptr *in_frame)
+		      const frame_info_ptr *in_frame,
+		      reg_buffer *regcache)
 {
   struct property_addr_info pinfo
     = {check_typedef (type), valaddr, addr, NULL};
@@ -2924,7 +2935,7 @@  resolve_dynamic_type (struct type *type,
   if (in_frame != nullptr)
     frame = *in_frame;
 
-  return resolve_dynamic_type_internal (type, &pinfo, frame, true);
+  return resolve_dynamic_type_internal (type, &pinfo, frame, regcache, true);
 }
 
 /* See gdbtypes.h  */
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index f80bd7e071a3..514af300de3b 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -2625,9 +2625,12 @@  extern CORE_ADDR get_pointer_type_max (struct type *);
    have a different type when resolved (depending on the contents of
    memory).  In this situation, 'is_dynamic_type' will still return
    true for the return value of this function.  */
+
+struct reg_buffer;
 extern struct type *resolve_dynamic_type
   (struct type *type, gdb::array_view<const gdb_byte> valaddr,
-   CORE_ADDR addr, const frame_info_ptr *frame = nullptr);
+   CORE_ADDR addr, const frame_info_ptr *frame = nullptr,
+   reg_buffer *regcache = nullptr);
 
 /* * Predicate if the type has dynamic values, which are not resolved yet.
    See the caveat in 'resolve_dynamic_type' to understand a scenario
diff --git a/gdb/gnu-v3-abi.c b/gdb/gnu-v3-abi.c
index aefbee542703..5cc0d1d2d4f4 100644
--- a/gdb/gnu-v3-abi.c
+++ b/gdb/gnu-v3-abi.c
@@ -493,7 +493,7 @@  gnuv3_baseclass_offset (struct type *type, int index,
       addr_stack.next = nullptr;
 
       CORE_ADDR result;
-      if (dwarf2_evaluate_property (&prop, nullptr, &addr_stack, &result,
+      if (dwarf2_evaluate_property (&prop, nullptr, nullptr, &addr_stack, &result,
 				    {addr_stack.addr}))
 	return (int) (result - addr_stack.addr);
     }
diff --git a/gdb/value.h b/gdb/value.h
index 13cfb007aa2c..802a49066288 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -1133,6 +1133,9 @@  extern struct value *value_from_register (struct type *type, int regnum,
 
 extern CORE_ADDR address_from_register (int regnum,
 					const frame_info_ptr &frame);
+struct reg_buffer;
+extern CORE_ADDR address_from_register (int regnum,
+					reg_buffer *regcache);
 
 extern struct value *value_of_variable (struct symbol *var,
 					const struct block *b);