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
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);