public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Zoran Zaric <zoran.zaric@amd.com>
To: <gdb-patches@sourceware.org>
Subject: [PATCH v4 15/28] Add to_gdb_value method to DWARF entry class
Date: Fri, 5 Nov 2021 11:38:36 +0000	[thread overview]
Message-ID: <20211105113849.118800-16-zoran.zaric@amd.com> (raw)
In-Reply-To: <20211105113849.118800-1-zoran.zaric@amd.com>

From: Zoran Zaric <Zoran.Zaric@amd.com>

The result of the DWARF expression evaluation is expected to be in a
format of a struct value object. This means that a new to_gdb_value
method is needed for both dwarf_location and dwarf_value classes.

In the case of the dwarf_value class, the conversion between that
class and struct value can happen often, this is why it is usefull to
cache once created struct value object in a dwarf_value
m_gdb_value member to reduce the number of conversions needed.
However, this also means that the to_gdb_value method cant be declared
as a constant method.

In the case of classes that derive from dwarf_location class, there is
now a need for a cloning method because the encapsulating
computed_closure class has a life span separated from the expression
evaluator.

gdb/ChangeLog:

        * dwarf2/expr.c (dwarf_entry::to_gdb_value): New method.
        (dwarf_location::to_gdb_value): New method.
        (dwarf_location::clone_location): New method.
        (dwarf_value::m_gdb_value): New member.
        (dwarf_value::to_gdb_value): New method.
        (dwarf_undefined::to_gdb_value): New method.
        (dwarf_undefined::clone_location): New method.
        (dwarf_memory::to_gdb_value): New method.
        (dwarf_memory::clone_location): New method.
        (dwarf_register::to_gdb_value): New method.
        (dwarf_register::clone_location): New method.
        (dwarf_implicit::to_gdb_value): New method.
        (dwarf_implicit::clone_location): New method.
        (dwarf_implicit_pointer::to_gdb_value): New method.
        (dwarf_implicit_pointer::clone_location): New method.
        (dwarf_composite::to_gdb_value): New method.
        (dwarf_composite::clone_location): New method.
---
 gdb/dwarf2/expr.c | 283 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 283 insertions(+)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index d76dddab643..ac26b4c5613 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -436,6 +436,10 @@ class dwarf_location : public dwarf_entry
 public:
   virtual ~dwarf_location () = default;
 
+  /* Clone the location and return the result as a
+     dwarf_location pointer.  */
+  virtual std::unique_ptr<dwarf_location> clone_location () const = 0;
+
   /* Add bit offset to the location description.  */
   void add_bit_offset (LONGEST bit_offset)
   {
@@ -588,6 +592,16 @@ class dwarf_location : public dwarf_entry
     return false;
   }
 
+  /* Convert DWARF location description to the matching struct value
+     representation of the given TYPE type in a given FRAME.
+     SUBOBJ_TYPE information if specified, will be used for more
+     precise description of the source variable type information.
+     Where SUBOBJ_OFFSET defines an offset into the DWARF entry
+     contents.  */
+  virtual value *to_gdb_value (frame_info *frame, struct type *type,
+			       struct type *subobj_type,
+			       LONGEST subobj_offset) const = 0;
+
 protected:
   /* Architecture of the location.  */
   gdbarch *m_arch;
@@ -670,6 +684,15 @@ class dwarf_value final : public dwarf_entry
     pack_long (m_contents.data (), type, value);
   }
 
+  dwarf_value (value *gdb_value)
+  {
+    m_type = value_type (gdb_value);
+    gdb::array_view<const gdb_byte> contents = value_contents_raw (gdb_value);
+    m_contents
+      = std::move (gdb::byte_vector (contents.begin (), contents.end ()));
+    m_gdb_value = gdb_value;
+  }
+
   gdb::array_view<const gdb_byte> contents () const
   {
     return m_contents;
@@ -694,12 +717,22 @@ class dwarf_value final : public dwarf_entry
      ARCH defines an architecture of the location described.  */
   dwarf_location_up to_location (struct gdbarch *arch) const;
 
+  /* Convert DWARF value to the matching struct value representation
+     of the given TYPE type.  Where OFFSET defines an offset into the
+     DWARF value contents.  */
+  value *to_gdb_value (struct type *type, LONGEST offset = 0);
+
 private:
   /* Value contents as a stream of bytes in target byte order.  */
   gdb::byte_vector m_contents;
 
   /* Type of the value held by the entry.  */
   struct type *m_type;
+
+  /* Struct value representation of the DWARF value.   Only used until
+     a set of arithmethic/logic operations that works with this class
+     are implemented.  */
+  value *m_gdb_value = nullptr;
 };
 
 using dwarf_value_up = std::unique_ptr<dwarf_value>;
@@ -741,6 +774,23 @@ dwarf_location::deref (frame_info *frame, const property_addr_info *addr_info,
     (gdb::array_view<const gdb_byte> (read_buf), type);
 }
 
+value *
+dwarf_value::to_gdb_value (struct type *type, LONGEST offset)
+{
+  if (m_gdb_value != nullptr)
+    return m_gdb_value;
+
+  size_t type_len = TYPE_LENGTH (type);
+
+  if (offset + type_len > TYPE_LENGTH (m_type))
+    invalid_synthetic_pointer ();
+
+  m_gdb_value = allocate_value (type);
+  memcpy (value_contents_raw (m_gdb_value).data (),
+	  m_contents.data () + offset, type_len);
+  return m_gdb_value;
+}
+
 /* Undefined location description entry.  This is a special location
    description type that describes the location description that is
    not known.  */
@@ -752,6 +802,11 @@ class dwarf_undefined final : public dwarf_location
     : dwarf_location (arch, 0)
   {}
 
+  dwarf_location_up clone_location () const override
+  {
+    return make_unique<dwarf_undefined> (*this);
+  }
+
   void read (frame_info *frame, gdb_byte *buf, int buf_bit_offset,
 	     size_t bit_size, LONGEST bits_to_skip, size_t location_bit_limit,
 	     bool big_endian, int *optimized, int *unavailable) const override
@@ -774,6 +829,19 @@ class dwarf_undefined final : public dwarf_location
   {
     return true;
   }
+
+  value *to_gdb_value (frame_info *frame, struct type *type,
+		       struct type *subobj_type,
+		       LONGEST subobj_offset) const override
+  {
+    gdb_assert (type != nullptr);
+    gdb_assert (subobj_type != nullptr);
+
+    value *retval = allocate_value (subobj_type);
+    mark_value_bytes_optimized_out (retval, subobj_offset,
+				    TYPE_LENGTH (subobj_type));
+    return retval;
+  }
 };
 
 class dwarf_memory final : public dwarf_location
@@ -783,6 +851,11 @@ class dwarf_memory final : public dwarf_location
     : dwarf_location (arch, offset), m_stack (stack)
   {}
 
+  dwarf_location_up clone_location () const override
+  {
+    return make_unique<dwarf_memory> (*this);
+  }
+
   void set_stack (bool stack)
   {
     m_stack = stack;
@@ -805,6 +878,10 @@ class dwarf_memory final : public dwarf_location
 				      struct type *type,
 				      size_t size = 0) const override;
 
+  value *to_gdb_value (frame_info *frame, struct type *type,
+		       struct type *subobj_type,
+		       LONGEST subobj_offset) const override;
+
 private:
   /* True if the location belongs to a stack memory region.  */
   bool m_stack;
@@ -996,6 +1073,27 @@ dwarf_memory::deref (frame_info *frame, const property_addr_info *addr_info,
     (gdb::array_view<const gdb_byte> (read_buf), type);
 }
 
+value *
+dwarf_memory::to_gdb_value (frame_info *frame, struct type *type,
+			    struct type *subobj_type,
+			    LONGEST subobj_offset) const
+{
+  gdb_assert (type != nullptr);
+  gdb_assert (subobj_type != nullptr);
+
+  struct type *ptr_type = builtin_type (m_arch)->builtin_data_ptr;
+
+  if (subobj_type->code () == TYPE_CODE_FUNC
+      || subobj_type->code () == TYPE_CODE_METHOD)
+    ptr_type = builtin_type (m_arch)->builtin_func_ptr;
+
+  CORE_ADDR address
+    = value_as_address (value_from_pointer (ptr_type, m_offset));
+  value *retval = value_at_lazy (subobj_type, address + subobj_offset);
+  set_value_stack (retval, m_stack);
+  return retval;
+}
+
 /* Register location description entry.  */
 
 class dwarf_register final : public dwarf_location
@@ -1005,6 +1103,11 @@ class dwarf_register final : public dwarf_location
     : dwarf_location (arch, offset), m_regnum (regnum)
   {}
 
+  dwarf_location_up clone_location () const override
+  {
+    return make_unique<dwarf_register> (*this);
+  }
+
   void read (frame_info *frame, gdb_byte *buf, int buf_bit_offset,
 	     size_t bit_size, LONGEST bits_to_skip, size_t location_bit_limit,
 	     bool big_endian, int *optimized, int *unavailable) const override;
@@ -1018,6 +1121,11 @@ class dwarf_register final : public dwarf_location
 			 LONGEST bits_to_skip, size_t bit_size,
 			 size_t location_bit_limit) const override;
 
+  value *to_gdb_value (frame_info *frame, struct type *type,
+		       struct type *subobj_type,
+		       LONGEST subobj_offset) const override;
+
+
 private:
   /* DWARF register number.  */
   unsigned int m_regnum;
@@ -1129,6 +1237,55 @@ dwarf_register::is_optimized_out (frame_info *frame, bool big_endian,
   return false;
 }
 
+value *
+dwarf_register::to_gdb_value (frame_info *frame, struct type *type,
+			      struct type *subobj_type,
+			      LONGEST subobj_offset) const
+{
+  gdb_assert (type != nullptr);
+  gdb_assert (subobj_type != nullptr);
+
+  gdbarch *frame_arch = get_frame_arch (frame);
+  int gdb_regnum = dwarf_reg_to_regnum_or_error (frame_arch, m_regnum);
+
+  if (frame == nullptr)
+    internal_error (__FILE__, __LINE__, _("invalid frame information"));
+
+  /* Construct the value.  */
+  value *retval
+    = gdbarch_value_from_register (frame_arch, type,
+				   gdb_regnum, get_frame_id (frame));
+
+  /* DWARF evaluator only supports targets with byte size of 8 bits,
+     while struct value offset is expressed in memory unit size.  */
+  int unit_size = gdbarch_addressable_memory_unit_size (m_arch);
+  LONGEST retval_offset = value_offset (retval) * unit_size;
+
+  if (type_byte_order (type) == BFD_ENDIAN_BIG
+      && TYPE_LENGTH (type) + m_offset < retval_offset)
+    /* Big-endian, and we want less than full size.  */
+    set_value_offset (retval, (retval_offset - m_offset) / unit_size);
+  else
+    set_value_offset (retval, (retval_offset + m_offset) / unit_size);
+
+  /* Get the data.  */
+  read_frame_register_value (retval, frame);
+
+  if (value_optimized_out (retval))
+    {
+      /* This means the register has undefined value / was not saved.
+	 As we're computing the location of some variable etc. in the
+	 program, not a value for inspecting a register ($pc, $sp, etc.),
+	 return a generic optimized out value instead, so that we show
+	 <optimized out> instead of <not saved>.  */
+      value *temp = allocate_value (subobj_type);
+      value_contents_copy (temp, 0, retval, 0, TYPE_LENGTH (subobj_type));
+      retval = temp;
+    }
+
+  return retval;
+}
+
 /* Implicit location description entry.  Describes a location
    description not found on the target but instead saved in a
    gdb-allocated buffer.  */
@@ -1144,6 +1301,11 @@ class dwarf_implicit final : public dwarf_location
       m_byte_order (byte_order)
   {}
 
+  dwarf_location_up clone_location () const override
+  {
+    return make_unique<dwarf_implicit> (*this);
+  }
+
   void read (frame_info *frame, gdb_byte *buf, int buf_bit_offset,
 	     size_t bit_size, LONGEST bits_to_skip, size_t location_bit_limit,
 	     bool big_endian, int *optimized, int *unavailable) const override;
@@ -1164,6 +1326,10 @@ class dwarf_implicit final : public dwarf_location
     return true;
   }
 
+  value *to_gdb_value (frame_info *frame, struct type *type,
+		       struct type *subobj_type,
+		       LONGEST subobj_offset) const override;
+
 private:
   /* Implicit location contents as a stream of bytes in target byte-order.  */
   gdb::byte_vector m_contents;
@@ -1211,6 +1377,36 @@ dwarf_implicit::read (frame_info *frame, gdb_byte *buf,
 		total_bits_to_skip, bit_size, big_endian);
 }
 
+value *
+dwarf_implicit::to_gdb_value (frame_info *frame, struct type *type,
+			      struct type *subobj_type,
+			      LONGEST subobj_offset) const
+{
+  gdb_assert (type != nullptr);
+  gdb_assert (subobj_type != nullptr);
+
+  size_t subtype_len = TYPE_LENGTH (subobj_type);
+  size_t type_len = TYPE_LENGTH (type);
+
+  /* To be compatible with expected error output of the existing
+     tests, the invalid synthetic pointer is not reported for
+     DW_OP_implicit_value operation.  */
+  if (subobj_offset + subtype_len > type_len
+      && m_byte_order != BFD_ENDIAN_UNKNOWN)
+    invalid_synthetic_pointer ();
+
+  value *retval = allocate_value (subobj_type);
+
+  /* The given offset is relative to the actual object.  */
+  if (m_byte_order == BFD_ENDIAN_BIG)
+    subobj_offset += m_contents.size () - type_len;
+
+  memcpy ((void *) value_contents_raw (retval).data (),
+	  (void *) (m_contents.data () + subobj_offset), subtype_len);
+
+  return retval;
+}
+
 /* Implicit pointer location description entry.  */
 
 class dwarf_implicit_pointer final : public dwarf_location
@@ -1226,6 +1422,11 @@ class dwarf_implicit_pointer final : public dwarf_location
       m_addr_size (addr_size), m_die_offset (die_offset)
   {}
 
+  dwarf_location_up clone_location () const override
+  {
+    return make_unique<dwarf_implicit_pointer> (*this);
+  }
+
   void read (frame_info *frame, gdb_byte *buf, int buf_bit_offset,
 	     size_t bit_size, LONGEST bits_to_skip, size_t location_bit_limit,
 	     bool big_endian, int *optimized, int *unavailable) const override;
@@ -1265,6 +1466,10 @@ class dwarf_implicit_pointer final : public dwarf_location
 				LONGEST bit_offset = 0,
 				int bit_length = 0) const override;
 
+  value *to_gdb_value (frame_info *frame, struct type *type,
+		       struct type *subobj_type,
+		       LONGEST subobj_offset) const override;
+
 private:
   /* Per object file data of the implicit pointer.  */
   dwarf2_per_objfile *m_per_objfile;
@@ -1328,6 +1533,26 @@ dwarf_implicit_pointer::indirect_implicit_ptr (frame_info *frame,
 				     m_per_cu, m_per_objfile, frame, type);
 }
 
+value *
+dwarf_implicit_pointer::to_gdb_value (frame_info *frame, struct type *type,
+				      struct type *subobj_type,
+				      LONGEST subobj_offset) const
+{
+  gdb_assert (type != nullptr);
+  gdb_assert (subobj_type != nullptr);
+
+  computed_closure *closure
+    = new computed_closure (make_unique<dwarf_implicit_pointer> (*this),
+			    get_frame_id (frame));
+  closure->incref ();
+
+  value *retval
+    = allocate_computed_value (subobj_type, &closure_value_funcs, closure);
+  set_value_offset (retval, subobj_offset);
+
+  return retval;
+}
+
 /* Composite location description entry.  */
 
 class dwarf_composite final : public dwarf_location
@@ -1337,6 +1562,11 @@ class dwarf_composite final : public dwarf_location
     : dwarf_location (arch, 0), m_per_cu (per_cu)
   {}
 
+  dwarf_location_up clone_location () const override
+  {
+    return make_unique<dwarf_composite> (*this);
+  }
+
   void add_piece (std::unique_ptr<dwarf_location> location, ULONGEST bit_size)
   {
     gdb_assert (location != nullptr);
@@ -1373,6 +1603,10 @@ class dwarf_composite final : public dwarf_location
 			 LONGEST bits_to_skip, size_t bit_size,
 			 size_t location_bit_limit) const override;
 
+  value *to_gdb_value (frame_info *frame, struct type *type,
+		       struct type *subobj_type,
+		       LONGEST subobj_offset) const override;
+
 private:
   /* Composite piece that contains a piece location
      description and it's size.  */
@@ -1383,6 +1617,17 @@ class dwarf_composite final : public dwarf_location
       : location (std::move (location)), size (size)
     {}
 
+    /* We need to make a piece copyiable, because dwarf_composite can be
+       copied / cloned.  */
+    piece (const piece &other)
+      : location (other.location->clone_location ()), size (other.size)
+    {}
+
+    piece (piece &&) = default;
+
+    void operator=(const piece &) = delete;
+    void operator=(piece &&) = delete;
+
     std::unique_ptr<dwarf_location> location;
     ULONGEST size;
   };
@@ -1682,6 +1927,44 @@ dwarf_composite::is_optimized_out (frame_info *frame, bool big_endian,
   return false;
 }
 
+value *
+dwarf_composite::to_gdb_value (frame_info *frame, struct type *type,
+			       struct type *subobj_type,
+			       LONGEST subobj_offset) const
+{
+  gdb_assert (type != nullptr);
+  gdb_assert (subobj_type != nullptr);
+
+  ULONGEST bit_size = 0;
+
+  for (const piece &piece : m_pieces)
+    bit_size += piece.size;
+
+  /* Complain if the expression is larger than the size of the
+     outer type.  */
+  if (bit_size > HOST_CHAR_BIT * TYPE_LENGTH (type))
+    invalid_synthetic_pointer ();
+
+  computed_closure *closure;
+
+  /* If compilation unit information is not available
+     we are in a CFI context.  */
+  if (m_per_cu == nullptr)
+    closure = new computed_closure (make_unique<dwarf_composite> (*this),
+				    frame);
+  else
+    closure = new computed_closure (make_unique<dwarf_composite> (*this),
+				    get_frame_id (frame));
+
+  closure->incref ();
+
+  value *retval
+    = allocate_computed_value (subobj_type, &closure_value_funcs, closure);
+  set_value_offset (retval, subobj_offset);
+
+  return retval;
+}
+
 static void *
 copy_value_closure (const value *v)
 {
-- 
2.17.1


  parent reply	other threads:[~2021-11-05 11:39 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-11-05 11:38 [PATCH v4 00/28] Allow location description on the DWARF stack Zoran Zaric
2021-11-05 11:38 ` [PATCH v4 01/28] Add new register access interface to expr.c Zoran Zaric
2021-12-14 20:34   ` Tom Tromey
2021-11-05 11:38 ` [PATCH v4 02/28] Add new memory " Zoran Zaric
2021-12-14 20:42   ` Tom Tromey
2021-11-05 11:38 ` [PATCH v4 03/28] Add new classes that model DWARF stack element Zoran Zaric
2021-12-14 21:10   ` Tom Tromey
2022-01-12 10:23     ` Zoran Zaric
2021-11-05 11:38 ` [PATCH v4 04/28] Add to_location method to dwarf_value class Zoran Zaric
2021-12-14 21:16   ` Tom Tromey
2022-01-12 10:51     ` Zoran Zaric
2021-11-05 11:38 ` [PATCH v4 05/28] Add to_value method to dwarf_location class Zoran Zaric
2021-12-14 21:34   ` Tom Tromey
2022-01-12 12:14     ` Zoran Zaric
2022-01-12 18:42       ` Zoran Zaric
2021-11-05 11:38 ` [PATCH v4 06/28] Add read method to location description classes Zoran Zaric
2021-11-05 11:38 ` [PATCH v4 07/28] Add write " Zoran Zaric
2021-11-05 11:38 ` [PATCH v4 08/28] Add deref " Zoran Zaric
2021-11-05 11:38 ` [PATCH v4 09/28] Add read_from_gdb_value method to dwarf_location Zoran Zaric
2021-11-05 11:38 ` [PATCH v4 10/28] Add write_to_gdb_value " Zoran Zaric
2021-11-05 11:38 ` [PATCH v4 11/28] Add is_implicit_ptr_at " Zoran Zaric
2021-11-05 11:38 ` [PATCH v4 12/28] Add indirect_implicit_ptr to dwarf_location class Zoran Zaric
2021-11-05 11:38 ` [PATCH v4 13/28] Add is_optimized_out " Zoran Zaric
2021-11-05 11:38 ` [PATCH v4 14/28] Add new computed struct value callback interface Zoran Zaric
2021-11-05 11:38 ` Zoran Zaric [this message]
2021-11-05 11:38 ` [PATCH v4 16/28] Change DWARF stack to use new dwarf_entry classes Zoran Zaric
2021-11-05 11:38 ` [PATCH v4 17/28] Remove old computed struct value callbacks Zoran Zaric
2021-11-05 11:38 ` [PATCH v4 18/28] Comments cleanup between expr.h and expr.c Zoran Zaric
2021-11-05 11:38 ` [PATCH v4 19/28] Remove dwarf_expr_context from expr.h interface Zoran Zaric
2021-11-05 11:38 ` [PATCH v4 20/28] Move read_addr_from_reg function to frame.c Zoran Zaric
2021-11-05 11:38 ` [PATCH v4 21/28] Add frame info check to DW_OP_reg operations Zoran Zaric
2021-11-05 11:38 ` [PATCH v4 22/28] Remove DWARF expression composition check Zoran Zaric
2021-11-05 11:38 ` [PATCH v4 23/28] Add support for any location description in CFI Zoran Zaric
2021-11-05 11:38 ` [PATCH v4 24/28] Add DWARF operations for byte and bit offset Zoran Zaric
2021-11-05 11:38 ` [PATCH v4 25/28] Add support for DW_OP_LLVM_undefined operation Zoran Zaric
2021-11-05 11:38 ` [PATCH v4 26/28] Add support for nested composite locations Zoran Zaric
2021-11-05 11:38 ` [PATCH v4 27/28] Add DW_OP_LLVM_extend DWARF operation Zoran Zaric
2021-11-05 11:38 ` [PATCH v4 28/28] Add DW_OP_LLVM_select_bit_piece " Zoran Zaric

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20211105113849.118800-16-zoran.zaric@amd.com \
    --to=zoran.zaric@amd.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).