public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v4 00/28] Allow location description on the DWARF stack
@ 2021-11-05 11:38 Zoran Zaric
  2021-11-05 11:38 ` [PATCH v4 01/28] Add new register access interface to expr.c Zoran Zaric
                   ` (27 more replies)
  0 siblings, 28 replies; 38+ messages in thread
From: Zoran Zaric @ 2021-11-05 11:38 UTC (permalink / raw)
  To: gdb-patches

Based on gdb master: c5967f38de59c7375970c09b2c8b8702a01eb9d2

The idea of this patch series is to allow a future extensions of the
DWARF expression evaluator needed for the upcoming vendor specific
DWARF extensions.

Main motivation behind this series of patches is AMD’s effort to
improve DWARF support for heavily optimized code, but more
specifically, optimized code for SIMD and SIMT architectures.

These patches are part of the AMD’s DWARF standard extensions that
can be found at:

https://llvm.org/docs/AMDGPUDwarfExtensionsForHeterogeneousDebugging.html

While trying to support optimized code for these architectures, we
found couple of restriction imposed by the version 5 of the standard:

- CFI describes restoring callee saved registers that are spilled.
  Currently CFI only allows a location description that is a register,
  memory address, or implicit location description. AMDGPU optimized
  code may spill scalar registers into portions of vector registers.
  This requires extending CFI to allow any location description.
 
- Optimized code may need to describe a variable that resides in pieces
  that are in different kinds of storage which may include parts that
  are in different kinds of memory address spaces. DWARF has the
  concept of segment addresses. However, the segment cannot be
  specified within a DWARF expression, which is only able to specify
  the offset portion of a segment address. The segment index is only
  provided by the entity that specifies the DWARF expression.
  Therefore, the segment index is a property that can only be put on
  complete objects, such as a variable. Another problem is with DWARF
  DW_OP_xderef* operations, which allow a value to be converted into
  an address of a specified address space which is then read. But it
  provides no way to create a memory location description for an
  address in the non-default address space.
 
- DW_OP_breg* treats the register as containing an address in the
  default address space. It is required to be able to specify the
  address space of the register value.
 
- There is really limited support for bit offsets of location
  description. This issue was already found by others who worked
  on packed array support for ADA language. The array could be packed
  in such a way that their start is not byte alligned. There is no way
  to describe this in DWARF, so gdb implementation in required for the
  packed array to be copied to the byte alligned addresses and then
  passed that buffer in the expression evaluator. This approach is
  restrictive for more complex scenarios.
 
All these restriction are caused by the fact that DWARF stack can only
hold values which size is not bigger then the size of the DWARF generic
type. This means that intermediate result of any DWARF operation needs
to fit in such a small representation.

DWARF Version 5 does not allow location descriptions to be entries on
the DWARF stack. They can only be the final result of the evaluation of
a DWARF expression. However, by allowing a location description to be a
first-class entry on the DWARF stack it becomes possible to compose
expressions containing both values and location descriptions naturally.
It allows objects to be located in any kind of memory address space,
in registers, be implicit values, be undefined, or a composite of any
of these.

This approach unifies the location description operations with general
operations. This in turn allows addition of new DWARF operations which
can push a memory location description with any offset and in any kind
of memory address space.

The number of registers and the cost of memory operations is much
higher for some architectures than a typical CPU. The compiler attempts
to optimize whole variables and arrays into registers. Currently DWARF
only allows DW_OP_push_object_address and related operations to work
with a global memory location. With this change, push object address
mechanism can be modified to work with any location description. This
would also removed the need for the passed in buffer mechanism that ADA
and GO languages currently use.

The proposed implementation in this patch series is completely backward
compatible with the DWARF 5 standard.

Although the patch series is designed as a whole, the first 23
patches could be viewed as a standalone subset that introduces the idea
of allowing location descriptions on the DWARF expression stack, while
last 5 take advantage of that functionality to implement new set of
DWARF operation which would not be possible without it.

Zoran Zaric (28):
  Add new register access interface to expr.c
  Add new memory access interface to expr.c
  Add new classes that model DWARF stack element
  Add to_location method to dwarf_value class
  Add to_value method to dwarf_location class
  Add read method to location description classes
  Add write method to location description classes
  Add deref method to location description classes
  Add read_from_gdb_value method to dwarf_location
  Add write_to_gdb_value method to dwarf_location
  Add is_implicit_ptr_at method to dwarf_location
  Add indirect_implicit_ptr to dwarf_location class
  Add is_optimized_out to dwarf_location class
  Add new computed struct value callback interface
  Add to_gdb_value method to DWARF entry class
  Change DWARF stack to use new dwarf_entry classes
  Remove old computed struct value callbacks
  Comments cleanup between expr.h and expr.c
  Remove dwarf_expr_context from expr.h interface
  Move read_addr_from_reg function to frame.c
  Add frame info check to DW_OP_reg operations
  Remove DWARF expression composition check
  Add support for any location description in CFI
  Add DWARF operations for byte and bit offset
  Add support for DW_OP_LLVM_undefined operation
  Add support for nested composite locations
  Add DW_OP_LLVM_extend DWARF operation
  Add DW_OP_LLVM_select_bit_piece DWARF operation

 gdb/ada-lang.c                                |    2 +-
 gdb/compile/compile-loc2c.c                   |   16 +
 gdb/dwarf2/expr.c                             | 4252 ++++++++++++-----
 gdb/dwarf2/expr.h                             |  272 +-
 gdb/dwarf2/frame.c                            |   74 +-
 gdb/dwarf2/loc.c                              |   57 +-
 gdb/f-lang.c                                  |    6 +-
 gdb/findvar.c                                 |    4 +-
 gdb/frame.c                                   |   45 +-
 gdb/testsuite/gdb.dwarf2/dw2-llvm-extend.exp  |  147 +
 gdb/testsuite/gdb.dwarf2/dw2-llvm-offset.exp  |  328 ++
 .../gdb.dwarf2/dw2-llvm-piece-end.exp         |  191 +
 .../gdb.dwarf2/dw2-llvm-select-bit-piece.exp  |  138 +
 .../gdb.dwarf2/dw2-llvm-undefined.exp         |  144 +
 gdb/testsuite/gdb.dwarf2/dw2-op-call.exp      |    2 +-
 gdb/testsuite/gdb.dwarf2/dw2-param-error.exp  |    2 +-
 .../gdb.dwarf2/dw2-stack-boundary.exp         |    2 +-
 gdb/testsuite/lib/dwarf.exp                   |   14 +
 gdb/valops.c                                  |  131 +-
 gdb/value.c                                   |   70 +-
 gdb/value.h                                   |    4 +-
 gdbsupport/common-utils.h                     |   18 +
 include/dwarf2.def                            |    8 +
 23 files changed, 4425 insertions(+), 1502 deletions(-)
 create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-llvm-extend.exp
 create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-llvm-offset.exp
 create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-llvm-piece-end.exp
 create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-llvm-select-bit-piece.exp
 create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-llvm-undefined.exp

-- 
2.17.1


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

* [PATCH v4 01/28] Add new register access interface to expr.c
  2021-11-05 11:38 [PATCH v4 00/28] Allow location description on the DWARF stack Zoran Zaric
@ 2021-11-05 11:38 ` Zoran Zaric
  2021-12-14 20:34   ` Tom Tromey
  2021-11-05 11:38 ` [PATCH v4 02/28] Add new memory " Zoran Zaric
                   ` (26 subsequent siblings)
  27 siblings, 1 reply; 38+ messages in thread
From: Zoran Zaric @ 2021-11-05 11:38 UTC (permalink / raw)
  To: gdb-patches

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

DWARF expression evaluator is currently using get_frame_register_bytes
and put_frame_register_bytes interface for register access.

The problem with evaluator using this interface is that it allows a
bleed out register access. This means that if the caller specifies a
larger amount of data then the size of a specified register, the
operation will continue accessing the neighboring registers until a
full amount of data has been reached.

DWARF specification does not define this behavior, so a new simplified
register access interface is needed instead.

	* dwarf2/expr.c (read_from_register): New function.
	(write_to_register): New function.
	(rw_pieced_value): Now calls the read_from_register and
	write_to_register functions.
---
 gdb/dwarf2/expr.c | 127 ++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 105 insertions(+), 22 deletions(-)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index 652161955d5..0ca8528298a 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -99,6 +99,96 @@ read_addr_from_reg (frame_info *frame, int reg)
   return address_from_register (regnum, frame);
 }
 
+/* Read register REGNUM's contents in a given FRAME context.
+
+   The data read is offsetted by OFFSET, and the number of bytes read
+   is defined by LENGTH.  The data is then copied into the
+   caller-managed buffer BUF.
+
+   If the register is optimized out or unavailable for the given
+   FRAME, the OPTIMIZED and UNAVAILABLE outputs are set
+   accordingly  */
+
+static void
+read_from_register (frame_info *frame, int regnum,
+		    CORE_ADDR offset, gdb::array_view<gdb_byte> buf,
+		    int *optimized, int *unavailable)
+{
+  gdbarch *arch = get_frame_arch (frame);
+  int regsize = register_size (arch, regnum);
+  int numregs = gdbarch_num_cooked_regs (arch);
+  int length = buf.size ();
+
+  /* If a register is wholly inside the OFFSET, skip it.  */
+  if (frame == NULL || !regsize
+      || offset + length > regsize || numregs < regnum)
+    {
+      *optimized = 0;
+      *unavailable = 1;
+      return;
+    }
+
+  gdb::byte_vector temp_buf (regsize);
+  enum lval_type lval;
+  CORE_ADDR address;
+  int realnum;
+
+  frame_register (frame, regnum, optimized, unavailable,
+		  &lval, &address, &realnum, temp_buf.data ());
+
+  if (!*optimized && !*unavailable)
+     memcpy (buf.data (), (char *) temp_buf.data () + offset, length);
+
+  return;
+}
+
+/* Write register REGNUM's contents in a given FRAME context.
+
+   The data written is offsetted by OFFSET, and the number of bytes
+   written is defined by LENGTH.  The data is copied from
+   caller-managed buffer BUF.
+
+   If the register is optimized out or unavailable for the given
+   FRAME, the OPTIMIZED and UNAVAILABLE outputs are set
+   accordingly. */
+
+static void
+write_to_register (frame_info *frame, int regnum,
+		   CORE_ADDR offset, gdb::array_view<gdb_byte> buf,
+		   int *optimized, int *unavailable)
+{
+  gdbarch *arch = get_frame_arch (frame);
+  int regsize = register_size (arch, regnum);
+  int numregs = gdbarch_num_cooked_regs (arch);
+  int length = buf.size ();
+
+  /* If a register is wholly inside of OFFSET, skip it.  */
+  if (frame == NULL || !regsize
+     || offset + length > regsize || numregs < regnum)
+    {
+      *optimized = 0;
+      *unavailable = 1;
+      return;
+    }
+
+  gdb::byte_vector temp_buf (regsize);
+  enum lval_type lval;
+  CORE_ADDR address;
+  int realnum;
+
+  frame_register (frame, regnum, optimized, unavailable,
+		  &lval, &address, &realnum, temp_buf.data ());
+
+  if (!*optimized && !*unavailable)
+    {
+      memcpy ((char *) temp_buf.data () + offset, buf.data (), length);
+
+      put_frame_register (frame, regnum, temp_buf.data ());
+    }
+
+  return;
+}
+
 struct piece_closure
 {
   /* Reference count.  */
@@ -242,24 +332,19 @@ rw_pieced_value (value *v, value *from, bool check_optimized)
 	    if (from == nullptr)
 	      {
 		/* Read mode.  */
-		if (!get_frame_register_bytes (frame, gdb_regnum,
-					       bits_to_skip / 8,
-					       buffer, &optim, &unavail))
+		read_from_register (frame, gdb_regnum, bits_to_skip / 8,
+				    buffer, &optim, &unavail);
+
+		if (optim)
 		  {
-		    if (optim)
-		      {
-			if (check_optimized)
-			  return true;
-			mark_value_bits_optimized_out (v, offset,
-						       this_size_bits);
-		      }
-		    if (unavail && !check_optimized)
-		      mark_value_bits_unavailable (v, offset,
-						   this_size_bits);
-		    break;
+		    if (check_optimized)
+		      return true;
+		    mark_value_bits_optimized_out (v, offset, this_size_bits);
 		  }
-
-		if (!check_optimized)
+		if (unavail)
+		  mark_value_bits_unavailable (v, offset, this_size_bits);
+		/* Only copy data if valid.  */
+		if (!optim && !unavail && !check_optimized)
 		  copy_bitwise (v_contents, offset,
 				buffer.data (), bits_to_skip % 8,
 				this_size_bits, bits_big_endian);
@@ -271,9 +356,8 @@ rw_pieced_value (value *v, value *from, bool check_optimized)
 		  {
 		    /* Data is copied non-byte-aligned into the register.
 		       Need some bits from original register value.  */
-		    get_frame_register_bytes (frame, gdb_regnum,
-					      bits_to_skip / 8,
-					      buffer, &optim, &unavail);
+		    read_from_register (frame, gdb_regnum, bits_to_skip / 8,
+					buffer, &optim, &unavail);
 		    if (optim)
 		      throw_error (OPTIMIZED_OUT_ERROR,
 				   _("Can't do read-modify-write to "
@@ -289,9 +373,8 @@ rw_pieced_value (value *v, value *from, bool check_optimized)
 		copy_bitwise (buffer.data (), bits_to_skip % 8,
 			      from_contents, offset,
 			      this_size_bits, bits_big_endian);
-		put_frame_register_bytes (frame, gdb_regnum,
-					  bits_to_skip / 8,
-					  buffer);
+		write_to_register (frame, gdb_regnum, bits_to_skip / 8,
+				   buffer, &optim, &unavail);
 	      }
 	  }
 	  break;
-- 
2.17.1


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

* [PATCH v4 02/28] Add new memory access interface to expr.c
  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-11-05 11:38 ` 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
                   ` (25 subsequent siblings)
  27 siblings, 1 reply; 38+ messages in thread
From: Zoran Zaric @ 2021-11-05 11:38 UTC (permalink / raw)
  To: gdb-patches

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

DWARF expression evaluator is currently using a few different
interfaces for memory access: write_memory_with_notification,
read_value_memory, read_memory.

They all seem incosistent, while some of them even need a struct
value typed argument to be present.

This patch is simplifying that interface by replacing it with two new
low level functions: read_from_memory and write_to_memory.

The advantage of this new interface is that it behaves in the same way
as the register access interface from the previous patch. Both of these
have the same error returning policy, which will be usefull for the
following patches.

	* dwarf2/expr.c (xfer_memory):  New function.
	(read_from_memory): New function.
	(write_to_memory): New function.
	(rw_pieced_value): Now calls the read_from_memory and
	write_to_memory functions.
---
 gdb/dwarf2/expr.c | 190 +++++++++++++++++++++++++++++++++++-----------
 1 file changed, 146 insertions(+), 44 deletions(-)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index 0ca8528298a..6419294a284 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -33,6 +33,8 @@
 #include "gdbsupport/underlying.h"
 #include "gdbarch.h"
 #include "objfiles.h"
+#include "inferior.h"
+#include "observable.h"
 
 /* Cookie for gdbarch data.  */
 
@@ -189,6 +191,86 @@ write_to_register (frame_info *frame, int regnum,
   return;
 }
 
+/* Helper for read_from_memory and write_to_memory.  */
+
+static void
+xfer_memory (CORE_ADDR address, gdb_byte *readbuf,
+	     const gdb_byte *writebuf,
+	     size_t length, bool stack, int *unavailable)
+{
+  *unavailable = 0;
+
+  target_object object
+    = stack ? TARGET_OBJECT_STACK_MEMORY : TARGET_OBJECT_MEMORY;
+
+  ULONGEST xfered_total = 0;
+
+  while (xfered_total < length)
+    {
+      ULONGEST xfered_partial;
+
+      enum target_xfer_status status
+	= target_xfer_partial (current_inferior ()->top_target (),
+			       object, NULL,
+			       (readbuf != nullptr
+				? readbuf + xfered_total
+				: nullptr),
+			       (writebuf != nullptr
+				? writebuf + xfered_total
+				: nullptr),
+			       address + xfered_total, length - xfered_total,
+			       &xfered_partial);
+
+      if (status == TARGET_XFER_OK)
+	{
+	  xfered_total += xfered_partial;
+	  QUIT;
+	}
+      else if (status == TARGET_XFER_UNAVAILABLE)
+	{
+	  *unavailable = 1;
+	  return;
+	}
+      else if (status == TARGET_XFER_EOF)
+	memory_error (TARGET_XFER_E_IO, address + xfered_total);
+      else
+	memory_error (status, address + xfered_total);
+    }
+}
+
+/* Read LENGTH bytes of memory contents starting at ADDRESS.
+
+   The data read is copied to a caller-managed buffer BUF.  STACK
+   indicates whether the memory range specified belongs to a stack
+   memory region.
+
+   If the memory is unavailable, the UNAVAILABLE output is set.  */
+
+static void
+read_from_memory (CORE_ADDR address, gdb_byte *buffer,
+		  size_t length, bool stack, int *unavailable)
+{
+  xfer_memory (address, buffer, nullptr, length, stack, unavailable);
+}
+
+/* Write LENGTH bytes of memory contents starting at ADDRESS.
+
+   The data written is copied from a caller-managed buffer buf.  STACK
+   indicates whether the memory range specified belongs to a stack
+   memory region.
+
+   If the memory is unavailable, the UNAVAILABLE output is set.  */
+
+static void
+write_to_memory (CORE_ADDR address, const gdb_byte *buffer,
+		 size_t length, bool stack, int *unavailable)
+{
+  xfer_memory (address, nullptr, buffer, length, stack, unavailable);
+
+  gdb::observers::memory_changed.notify (current_inferior (), address,
+					 length, buffer);
+}
+
 struct piece_closure
 {
   /* Reference count.  */
@@ -387,66 +469,86 @@ rw_pieced_value (value *v, value *from, bool check_optimized)
 	    bits_to_skip += p->offset;
 
 	    CORE_ADDR start_addr = p->v.mem.addr + bits_to_skip / 8;
+	    bool in_stack_memory = p->v.mem.in_stack_memory;
+	    int unavail = 0;
 
 	    if (bits_to_skip % 8 == 0 && this_size_bits % 8 == 0
 		&& offset % 8 == 0)
 	      {
 		/* Everything is byte-aligned; no buffer needed.  */
-		if (from != nullptr)
-		  write_memory_with_notification (start_addr,
-						  (from_contents
-						   + offset / 8),
-						  this_size_bits / 8);
+		if (from != NULL)
+		  write_to_memory (start_addr, (from_contents + offset / 8),
+				   this_size_bits / 8, in_stack_memory,
+				   &unavail);
 		else
-		  read_value_memory (v, offset,
-				     p->v.mem.in_stack_memory,
-				     p->v.mem.addr + bits_to_skip / 8,
-				     v_contents + offset / 8,
-				     this_size_bits / 8);
-		break;
-	      }
-
-	    this_size = bits_to_bytes (bits_to_skip, this_size_bits);
-	    buffer.resize (this_size);
-
-	    if (from == nullptr)
-	      {
-		/* Read mode.  */
-		read_value_memory (v, offset,
-				   p->v.mem.in_stack_memory,
-				   p->v.mem.addr + bits_to_skip / 8,
-				   buffer.data (), this_size);
-		copy_bitwise (v_contents, offset,
-			      buffer.data (), bits_to_skip % 8,
-			      this_size_bits, bits_big_endian);
+		  read_from_memory (start_addr, (v_contents + offset / 8),
+				    this_size_bits / 8, in_stack_memory,
+				    &unavail);
 	      }
 	    else
 	      {
-		/* Write mode.  */
-		if (bits_to_skip % 8 != 0 || this_size_bits % 8 != 0)
+		this_size = bits_to_bytes (bits_to_skip, this_size_bits);
+		buffer.resize (this_size);
+
+		if (from == NULL)
 		  {
-		    if (this_size <= 8)
+		    /* Read mode.  */
+		    read_from_memory (start_addr, buffer.data (),
+				      this_size, in_stack_memory,
+				      &unavail);
+		    if (!unavail)
+		      copy_bitwise (v_contents, offset,
+				    buffer.data (), bits_to_skip % 8,
+				    this_size_bits, bits_big_endian);
+		  }
+		else
+		  {
+		    /* Write mode.  */
+		    if (bits_to_skip % 8 != 0 || this_size_bits % 8 != 0)
 		      {
-			/* Perform a single read for small sizes.  */
-			read_memory (start_addr, buffer.data (),
-				     this_size);
+			if (this_size <= 8)
+			  {
+			    /* Perform a single read for small sizes.  */
+			    read_from_memory (start_addr, buffer.data (),
+					      this_size, in_stack_memory,
+					      &unavail);
+			  }
+			else
+			  {
+			    /* Only the first and last bytes can possibly have
+			       any bits reused.  */
+			    read_from_memory (start_addr, buffer.data (),
+					      1, in_stack_memory,
+					      &unavail);
+			    if (!unavail)
+			      read_from_memory (start_addr + this_size - 1,
+						&buffer[this_size - 1], 1,
+						in_stack_memory, &unavail);
+			  }
 		      }
-		    else
+
+		    if (!unavail)
 		      {
-			/* Only the first and last bytes can possibly have
-			   any bits reused.  */
-			read_memory (start_addr, buffer.data (), 1);
-			read_memory (start_addr + this_size - 1,
-				     &buffer[this_size - 1], 1);
+			copy_bitwise (buffer.data (), bits_to_skip % 8,
+				      from_contents, offset,
+				      this_size_bits, bits_big_endian);
+			write_to_memory (start_addr, buffer.data (),
+					 this_size, in_stack_memory,
+					 &unavail);
 		      }
 		  }
+	      }
 
-		copy_bitwise (buffer.data (), bits_to_skip % 8,
-			      from_contents, offset,
-			      this_size_bits, bits_big_endian);
-		write_memory_with_notification (start_addr,
-						buffer.data (),
-						this_size);
+	    if (unavail)
+	      {
+		if (from == NULL)
+		  mark_value_bits_unavailable (v, (offset + bits_to_skip % 8),
+					       this_size_bits);
+		else
+		  throw_error (NOT_AVAILABLE_ERROR,
+			       _("Can't do read-modify-write to "
+				 "update bitfield; containing word "
+				 "is unavailable"));
 	      }
 	  }
 	  break;
-- 
2.17.1


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

* [PATCH v4 03/28] Add new classes that model DWARF stack element
  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-11-05 11:38 ` [PATCH v4 02/28] Add new memory " Zoran Zaric
@ 2021-11-05 11:38 ` Zoran Zaric
  2021-12-14 21:10   ` Tom Tromey
  2021-11-05 11:38 ` [PATCH v4 04/28] Add to_location method to dwarf_value class Zoran Zaric
                   ` (24 subsequent siblings)
  27 siblings, 1 reply; 38+ messages in thread
From: Zoran Zaric @ 2021-11-05 11:38 UTC (permalink / raw)
  To: gdb-patches

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

The rest of the patch series addresses the issues described in a
"Motivation" section of the AMD’s DWARF standard extensions that
can be found at:

https://llvm.org/docs/AMDGPUDwarfExtensionsForHeterogeneousDebugging.html

The document describes a couple of main issues found when using the
current DWARF 5 version to describe optimized code for SIMD and SIMT
architectures.

Without going much into details described in the document, the main
point is that DWARF version 5 does not allow a proper support for
address spaces and it does not allow a location description to be used
anywhere in the DWARF expression, instead a location description can
using a result left on the DWARF stack (after the evaluation of that
expression) to describe the location.

Both issues can be solved in a clean way by introducing a new set of
classes that describe all entry types which can be placed on a DWARF
stack, while keeping most of backward compatibility with the previous
standard version. These entry types can now be either a typed value
or any location description.

Known edge case where placing a location description on the DWARF stack
is not fully backward compatible with DWARF version 5 is in the case of
DW_OP_call operations, where the current standard only defines that an
expression stack is shared between the caller and the callee, but there
it is unknown what happens with the resuling location description after
the evaluation of the callee's location description expression.

Considering that this edge case is not defined in the standard, it
would be very unusual and dangerous for any compiler to use it in their
own way and in the existing testsuite, there is no indication of that.

Currently, the result of an expression evaluation is kept in a separate
data structure, while with the new approach, it will be always found as
a top element of the DWARF stack.

Question here is, why do we need a new set of classes and why not just
use the struct value instead?

As it stands, there are couple of issues with using the struct value to
describe a DWARF stack element:

 - It is not designed to represent a DWARF location description
specifically, instead it behaves more like unified debug information
format that represents an actual target resource. One example of this
is accessing data of a struct value register location description,
where if the amount of data accessed is larger then the register,
results in accessing more then one register. In DWARF this is not a
valid behavior and locations that span more then one register should be
described as a composite location description.

- There is a tight coupling between struct value and it’s type
information, regardless if the data represented is describing a value
(not_lval) or a location description. While the type information
dictates how the data is accessed for a struct value case, in DWARF,
location description doesn’t have a type so data access is not bound by
it.

- DWARF values only support much simpler base types, while struct value
can be linked to any type. Admittedly, new classes are still using the
same struct value infrastructure for a value based operations at the
moment, but that is planned to change in the near future.

- struct value register location description requires a frame id
information which makes them unsuitable for CFA expression evaluation.

So, there seems to be a lack of separation of concerns in the design
of a struct value infrastructure, while the new classes are handling
one specific purpose and are completely encapsulated in the expr.c.

Additional benefit of this design is that it makes a step in a
right direction for being able to evaluate DWARF expressions on a
gdbserver side in the near future, which sounds like a desirable thing.

It is also worth mentioning that this new location description
representation is based on a bit granularity (the bit_suboffset class
member) even though the DWARF standard has a very limited support for
it (mostly used for DW_OP_bit_piece operation).

By allowing any location description to define a bit sub-offset of the
location, we are able to give more options for supporting of new
concepts (like the existing packed arrays in Ada language).

In this patch, a new set of classes that describe a DWARF stack element
are added. The new classes are:

- Value - describes a numerical value with a DWARF base type.
- Location description - describes a DWARF location description.
  - Undefined location - describes a location that is not defined.
  - Memory location - describes a location in memory.
  - Register location - describes a register location in a frame
    context.
  - Implicit location - describes a location that implicitly holds a
    value that it describes.
  - Implicit pointer - describes a concept of an implicit pointer to
    a source variable.
  - Composite location - describes a location that is composed from
    pieces of other location descriptions.

For now, these classes are just defined, and they are planned to be
used by the following patches.

gdb/ChangeLog:

	* dwarf2/expr.c (class dwarf_entry): New class.
	(class dwarf_value): New class.
	(class dwarf_location): New class.
	(class dwarf_undefined): New class.
	(class dwarf_memory): New class.
	(class dwarf_register): New class.
	(class dwarf_implicit): New class.
	(class dwarf_implicit_pointer): New class.
	(class dwarf_composite): New class.
	* value.c (pack_unsigned_long): Expose function.
	* value.h (pack_unsigned_long): Expose function.
---
 gdb/dwarf2/expr.c | 241 ++++++++++++++++++++++++++++++++++++++++++++++
 gdb/value.c       |   2 +-
 gdb/value.h       |   2 +
 3 files changed, 244 insertions(+), 1 deletion(-)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index 6419294a284..6363bcc4707 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -271,6 +271,247 @@ write_to_memory (CORE_ADDR address, const gdb_byte *buffer,
 					 length, buffer);
 }
 
+/* Base class that describes entries found on a DWARF expression
+   evaluation stack.  */
+
+class dwarf_entry
+{
+protected:
+  /* Not expected to be called on it's own.  */
+  dwarf_entry () = default;
+
+public:
+  virtual ~dwarf_entry () = default;
+};
+
+/* Location description entry found on a DWARF expression evaluation
+   stack.
+
+   Types of locations descirbed can be: register location, memory
+   location, implicit location, implicit pointer location, undefined
+   location and composite location (composed out of any of the location
+   types including another composite location).  */
+
+class dwarf_location : public dwarf_entry
+{
+protected:
+  /* Not expected to be called on it's own.  */
+  dwarf_location (gdbarch *arch, LONGEST offset)
+    : m_arch (arch), m_offset (offset)
+  {}
+
+public:
+  virtual ~dwarf_location () = default;
+
+  /* Add bit offset to the location description.  */
+  void add_bit_offset (LONGEST bit_offset)
+  {
+    LONGEST bit_total_offset = m_bit_suboffset + bit_offset;
+
+    m_offset += bit_total_offset / HOST_CHAR_BIT;
+    m_bit_suboffset = bit_total_offset % HOST_CHAR_BIT;
+  };
+
+  void set_initialised (bool initialised)
+  {
+    m_initialised = initialised;
+  };
+
+protected:
+  /* Architecture of the location.  */
+  gdbarch *m_arch;
+
+  /* Byte offset into the location.  */
+  LONGEST m_offset;
+
+  /* Bit suboffset of the last byte.  */
+  LONGEST m_bit_suboffset = 0;
+
+  /* Whether the location is initialized.  Used for non-standard
+     DW_OP_GNU_uninit operation.  */
+  bool m_initialised = true;
+};
+
+/* Value entry found on a DWARF expression evaluation stack.  */
+
+class dwarf_value final : public dwarf_entry
+{
+public:
+  dwarf_value (gdb::array_view<const gdb_byte> contents, struct type *type)
+    : m_contents (contents.begin (), contents.end ()), m_type (type)
+  {}
+
+  dwarf_value (ULONGEST value, struct type *type)
+    : m_contents (TYPE_LENGTH (type)), m_type (type)
+  {
+    pack_unsigned_long (m_contents.data (), type, value);
+  }
+
+  dwarf_value (LONGEST value, struct type *type)
+    : m_contents (TYPE_LENGTH (type)), m_type (type)
+  {
+    pack_long (m_contents.data (), type, value);
+  }
+
+  gdb::array_view<const gdb_byte> contents () const
+  {
+    return m_contents;
+  }
+
+  struct type *type ()
+  {
+    return m_type;
+  }
+
+  const struct type *type () const
+  {
+    return m_type;
+  }
+
+  LONGEST to_long () const
+  {
+    return unpack_long (m_type, m_contents.data ());
+  }
+
+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;
+};
+
+/* Undefined location description entry.  This is a special location
+   description type that describes the location description that is
+   not known.  */
+
+class dwarf_undefined final : public dwarf_location
+{
+public:
+  dwarf_undefined (gdbarch *arch)
+    : dwarf_location (arch, 0)
+  {}
+};
+
+class dwarf_memory final : public dwarf_location
+{
+public:
+  dwarf_memory (gdbarch *arch, LONGEST offset, bool stack = false)
+    : dwarf_location (arch, offset), m_stack (stack)
+  {}
+
+  void set_stack (bool stack)
+  {
+    m_stack = stack;
+  };
+
+private:
+  /* True if the location belongs to a stack memory region.  */
+  bool m_stack;
+};
+
+/* Register location description entry.  */
+
+class dwarf_register final : public dwarf_location
+{
+public:
+  dwarf_register (gdbarch *arch, unsigned int regnum, LONGEST offset = 0)
+    : dwarf_location (arch, offset), m_regnum (regnum)
+  {}
+
+private:
+  /* DWARF register number.  */
+  unsigned int m_regnum;
+};
+
+/* Implicit location description entry.  Describes a location
+   description not found on the target but instead saved in a
+   gdb-allocated buffer.  */
+
+class dwarf_implicit final : public dwarf_location
+{
+public:
+
+  dwarf_implicit (gdbarch *arch, gdb::array_view<const gdb_byte> contents,
+		  enum bfd_endian byte_order)
+    : dwarf_location (arch, 0),
+      m_contents (contents.begin (), contents.end ()),
+      m_byte_order (byte_order)
+  {}
+
+private:
+  /* Implicit location contents as a stream of bytes in target byte-order.  */
+  gdb::byte_vector m_contents;
+
+  /* Contents original byte order.  */
+  bfd_endian m_byte_order;
+};
+
+/* Implicit pointer location description entry.  */
+
+class dwarf_implicit_pointer final : public dwarf_location
+{
+public:
+  dwarf_implicit_pointer (gdbarch *arch,
+			  dwarf2_per_objfile *per_objfile,
+			  dwarf2_per_cu_data *per_cu,
+			  int addr_size, sect_offset die_offset,
+			  LONGEST offset)
+    : dwarf_location (arch, offset),
+      m_per_objfile (per_objfile), m_per_cu (per_cu),
+      m_addr_size (addr_size), m_die_offset (die_offset)
+  {}
+
+private:
+  /* Per object file data of the implicit pointer.  */
+  dwarf2_per_objfile *m_per_objfile;
+
+  /* Compilation unit context of the implicit pointer.  */
+  dwarf2_per_cu_data *m_per_cu;
+
+  /* Address size for the evaluation.  */
+  int m_addr_size;
+
+  /* DWARF die offset pointed by the implicit pointer.  */
+  sect_offset m_die_offset;
+};
+
+/* Composite location description entry.  */
+
+class dwarf_composite final : public dwarf_location
+{
+public:
+  dwarf_composite (gdbarch *arch, dwarf2_per_cu_data *per_cu)
+    : dwarf_location (arch, 0), m_per_cu (per_cu)
+  {}
+
+  void add_piece (std::unique_ptr<dwarf_location> location, ULONGEST bit_size)
+  {
+    gdb_assert (location != nullptr);
+    m_pieces.emplace_back (std::move (location), bit_size);
+  }
+
+private:
+  /* Composite piece that contains a piece location
+     description and it's size.  */
+  struct piece
+  {
+  public:
+    piece (std::unique_ptr<dwarf_location> location, ULONGEST size)
+      : location (std::move (location)), size (size)
+    {}
+
+    std::unique_ptr<dwarf_location> location;
+    ULONGEST size;
+  };
+
+  /* Compilation unit context of the pointer.  */
+  dwarf2_per_cu_data *m_per_cu;
+
+  /* Vector of composite pieces.  */
+  std::vector<piece> m_pieces;
+};
+
 struct piece_closure
 {
   /* Reference count.  */
diff --git a/gdb/value.c b/gdb/value.c
index 998bec321a2..7de858c7085 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -3476,7 +3476,7 @@ pack_long (gdb_byte *buf, struct type *type, LONGEST num)
 
 /* Pack NUM into BUF using a target format of TYPE.  */
 
-static void
+void
 pack_unsigned_long (gdb_byte *buf, struct type *type, ULONGEST num)
 {
   LONGEST len;
diff --git a/gdb/value.h b/gdb/value.h
index aa105645034..82b29c6292e 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -678,6 +678,8 @@ extern struct value *value_field_bitfield (struct type *type, int fieldno,
 					   const struct value *val);
 
 extern void pack_long (gdb_byte *buf, struct type *type, LONGEST num);
+extern void pack_unsigned_long (gdb_byte *buf, struct type *type,
+				ULONGEST num);
 
 extern struct value *value_from_longest (struct type *type, LONGEST num);
 extern struct value *value_from_ulongest (struct type *type, ULONGEST num);
-- 
2.17.1


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

* [PATCH v4 04/28] Add to_location method to dwarf_value class
  2021-11-05 11:38 [PATCH v4 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (2 preceding siblings ...)
  2021-11-05 11:38 ` [PATCH v4 03/28] Add new classes that model DWARF stack element Zoran Zaric
@ 2021-11-05 11:38 ` Zoran Zaric
  2021-12-14 21:16   ` Tom Tromey
  2021-11-05 11:38 ` [PATCH v4 05/28] Add to_value method to dwarf_location class Zoran Zaric
                   ` (23 subsequent siblings)
  27 siblings, 1 reply; 38+ messages in thread
From: Zoran Zaric @ 2021-11-05 11:38 UTC (permalink / raw)
  To: gdb-patches

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

DWARF standard already contains an implicit conversion between location
description and a DWARF value. In the DWARF 5 version, one place
where this can happen is at the very end of the evaluation where a
client decides if the result is expected to be in a form of a value or
a location description (as_lval argument of the new evaluation method).

By allowing any location description to be on the DWARF stack, these
implicit conversions are expected on per operation basis which means
that the new dwarf_value class need to have a support for it.

This patch adds a conversion method from a dwarf_value object into a
location description object.

To support the conversion method we also need an implementation of the
C++14 standard library function make_unique which was copied from the
standard library implementation.

gdb/ChangeLog:

        * dwarf2/expr.c (class dwarf_value::to_location): New method.

gdbsupport/ChangeLog:

        * common-utils.h (make_unique): New function.
---
 gdb/dwarf2/expr.c         | 25 +++++++++++++++++++++++++
 gdbsupport/common-utils.h | 18 ++++++++++++++++++
 2 files changed, 43 insertions(+)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index 6363bcc4707..2cb93706ac4 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -271,6 +271,8 @@ write_to_memory (CORE_ADDR address, const gdb_byte *buffer,
 					 length, buffer);
 }
 
+class dwarf_location;
+
 /* Base class that describes entries found on a DWARF expression
    evaluation stack.  */
 
@@ -284,6 +286,8 @@ class dwarf_entry
   virtual ~dwarf_entry () = default;
 };
 
+using dwarf_entry_up = std::unique_ptr<dwarf_entry>;
+
 /* Location description entry found on a DWARF expression evaluation
    stack.
 
@@ -332,6 +336,8 @@ class dwarf_location : public dwarf_entry
   bool m_initialised = true;
 };
 
+using dwarf_location_up = std::unique_ptr<dwarf_location>;
+
 /* Value entry found on a DWARF expression evaluation stack.  */
 
 class dwarf_value final : public dwarf_entry
@@ -373,6 +379,10 @@ class dwarf_value final : public dwarf_entry
     return unpack_long (m_type, m_contents.data ());
   }
 
+  /* Convert DWARF value into a DWARF memory location description.
+     ARCH defines an architecture of the location described.  */
+  dwarf_location_up to_location (struct gdbarch *arch) const;
+
 private:
   /* Value contents as a stream of bytes in target byte order.  */
   gdb::byte_vector m_contents;
@@ -410,6 +420,21 @@ class dwarf_memory final : public dwarf_location
   bool m_stack;
 };
 
+dwarf_location_up
+dwarf_value::to_location (struct gdbarch *arch) const
+{
+  LONGEST offset;
+
+  if (gdbarch_integer_to_address_p (arch))
+    offset = gdbarch_integer_to_address (arch, m_type, m_contents.data ());
+  else
+    offset = extract_unsigned_integer (m_contents.data (),
+				       TYPE_LENGTH (m_type),
+				       type_byte_order (m_type));
+
+  return make_unique<dwarf_memory> (arch, offset);
+}
+
 /* Register location description entry.  */
 
 class dwarf_register final : public dwarf_location
diff --git a/gdbsupport/common-utils.h b/gdbsupport/common-utils.h
index 224e1f31222..be1b805f7c8 100644
--- a/gdbsupport/common-utils.h
+++ b/gdbsupport/common-utils.h
@@ -206,4 +206,22 @@ extern int hex2bin (const char *hex, gdb_byte *bin, int count);
 /* Like the above, but return a gdb::byte_vector.  */
 gdb::byte_vector hex2bin (const char *hex);
 
+#if __cplusplus >= 201402L
+#include <memory>
+
+using std::make_unique;
+#else
+namespace gdb {
+
+/* Stolen from libstdc++ and adjusted, so probably fine license-wise.  */
+template<typename _Tp, typename ... _Args>
+std::unique_ptr<_Tp>
+make_unique (_Args &&... __args)
+{
+  return std::unique_ptr<_Tp> (new _Tp (std::forward<_Args>(__args)...));
+}
+
+}
+#endif /* __cplusplus >= 201402L */
+
 #endif /* COMMON_COMMON_UTILS_H */
-- 
2.17.1


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

* [PATCH v4 05/28] Add to_value method to dwarf_location class
  2021-11-05 11:38 [PATCH v4 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (3 preceding siblings ...)
  2021-11-05 11:38 ` [PATCH v4 04/28] Add to_location method to dwarf_value class Zoran Zaric
@ 2021-11-05 11:38 ` Zoran Zaric
  2021-12-14 21:34   ` Tom Tromey
  2021-11-05 11:38 ` [PATCH v4 06/28] Add read method to location description classes Zoran Zaric
                   ` (22 subsequent siblings)
  27 siblings, 1 reply; 38+ messages in thread
From: Zoran Zaric @ 2021-11-05 11:38 UTC (permalink / raw)
  To: gdb-patches

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

Following the idea from the last patch this patch is adding a
conversion method from any dwarf_location derived object into
a dwarf_value object.

Currently, we only know how to convert from a memory location
description into a value, but it is resonable to expect a set
of target hooks that would let the target decide on how to do
other conversions in the future.

gdb/ChangeLog:

        * dwarf2/expr.c (dwarf_location::to_value): New method.
        (dwarf_memory::to_value): New method.
        (ill_formed_expression): New function.
---
 gdb/dwarf2/expr.c | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index 2cb93706ac4..e9e5e55ca61 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -90,6 +90,14 @@ bits_to_bytes (ULONGEST start, ULONGEST n_bits)
   return (start % HOST_CHAR_BIT + n_bits + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT;
 }
 
+/* Throw an exception about the invalid DWARF expression.  */
+
+static void ATTRIBUTE_NORETURN
+ill_formed_expression ()
+{
+  error (_("Ill-formed DWARF expression"));
+}
+
 /* See expr.h.  */
 
 CORE_ADDR
@@ -272,6 +280,7 @@ write_to_memory (CORE_ADDR address, const gdb_byte *buffer,
 }
 
 class dwarf_location;
+class dwarf_value;
 
 /* Base class that describes entries found on a DWARF expression
    evaluation stack.  */
@@ -321,6 +330,16 @@ class dwarf_location : public dwarf_entry
     m_initialised = initialised;
   };
 
+  /* Convert DWARF entry into a DWARF value.  TYPE defines a desired type of
+     the returned DWARF value if it doesn't already have one.
+
+     If the conversion from that location description kind to a value is not
+     supported, throw an error.  */
+  virtual std::unique_ptr<dwarf_value> to_value (struct type *type) const
+  {
+    ill_formed_expression ();
+  }
+
 protected:
   /* Architecture of the location.  */
   gdbarch *m_arch;
@@ -391,6 +410,8 @@ class dwarf_value final : public dwarf_entry
   struct type *m_type;
 };
 
+using dwarf_value_up = std::unique_ptr<dwarf_value>;
+
 /* Undefined location description entry.  This is a special location
    description type that describes the location description that is
    not known.  */
@@ -415,6 +436,8 @@ class dwarf_memory final : public dwarf_location
     m_stack = stack;
   };
 
+  dwarf_value_up to_value (struct type *type) const override;
+
 private:
   /* True if the location belongs to a stack memory region.  */
   bool m_stack;
@@ -435,6 +458,12 @@ dwarf_value::to_location (struct gdbarch *arch) const
   return make_unique<dwarf_memory> (arch, offset);
 }
 
+dwarf_value_up
+dwarf_memory::to_value (struct type *type) const
+{
+  return make_unique<dwarf_value> (m_offset, type);
+}
+
 /* Register location description entry.  */
 
 class dwarf_register final : public dwarf_location
-- 
2.17.1


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

* [PATCH v4 06/28] Add read method to location description classes
  2021-11-05 11:38 [PATCH v4 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (4 preceding siblings ...)
  2021-11-05 11:38 ` [PATCH v4 05/28] Add to_value method to dwarf_location class Zoran Zaric
@ 2021-11-05 11:38 ` Zoran Zaric
  2021-11-05 11:38 ` [PATCH v4 07/28] Add write " Zoran Zaric
                   ` (21 subsequent siblings)
  27 siblings, 0 replies; 38+ messages in thread
From: Zoran Zaric @ 2021-11-05 11:38 UTC (permalink / raw)
  To: gdb-patches

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

After adding the interface for register and memory location access, a
new method for reading from any location derived from a dwarf_location
class, can now be defined.

In the case of implicit pointer location description the existing
indirect_synthetic_pointer interface requiers a type of the pointer
to be specified, so for a generic read interface the only type that
makes sense is the DWARF generic type. This means that the existing
address_type method of a dwarf_expr_context class needs to be exposed
outside of that class.

gdb/ChangeLog:

        * dwarf2/expr.c (dwarf_location::read): New method.
        (dwarf_undefined::read): New method.
        (dwarf_memory::read): New method.
        (dwarf_register::read): New method.
        (dwarf_implicit::read): New method.
        (dwarf_implicit_pointer::read): New method.
        (dwarf_composite::read): New method.
        (dwarf_expr_context::address_type): Change to use the new
        address_type function.
        (address_type): New function.
---
 gdb/dwarf2/expr.c | 305 ++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 284 insertions(+), 21 deletions(-)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index e9e5e55ca61..f2349208412 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -279,6 +279,36 @@ write_to_memory (CORE_ADDR address, const gdb_byte *buffer,
 					 length, buffer);
 }
 
+/* Return the type used for DWARF operations where the type is
+   generic in the DWARF spec, the ARCH is a target architecture
+   of the type and ADDR_SIZE is expected size of the address.
+   Only certain sizes are supported.  */
+
+static type *
+address_type (gdbarch *arch, int addr_size)
+{
+  dwarf_gdbarch_types *types
+    = (dwarf_gdbarch_types *) gdbarch_data (arch, dwarf_arch_cookie);
+  int ndx;
+
+  if (addr_size == 2)
+    ndx = 0;
+  else if (addr_size == 4)
+    ndx = 1;
+  else if (addr_size == 8)
+    ndx = 2;
+  else
+    error (_("Unsupported address size in DWARF expressions: %d bits"),
+	   HOST_CHAR_BIT * addr_size);
+
+  if (types->dw_types[ndx] == nullptr)
+    types->dw_types[ndx]
+      = arch_integer_type (arch, HOST_CHAR_BIT * addr_size,
+			   0, "<signed DWARF address type>");
+
+  return types->dw_types[ndx];
+}
+
 class dwarf_location;
 class dwarf_value;
 
@@ -340,6 +370,27 @@ class dwarf_location : public dwarf_entry
     ill_formed_expression ();
   }
 
+  /* Read contents from the described location.
+
+     The read operation is performed in the context of a FRAME.
+     BIT_SIZE is the number of bits to read.  The data read is copied
+     to the caller-managed buffer BUF.  BIG_ENDIAN defines the
+     endianness of the target.  BITS_TO_SKIP is a bit offset into the
+     location and BUF_BIT_OFFSET is buffer BUF's bit offset.
+     LOCATION_BIT_LIMIT is a maximum number of bits that location can
+     hold, where value zero signifies that there is no such
+     restriction.
+
+     Note that some location types can be read without a FRAME context.
+
+     If the location is optimized out or unavailable, the OPTIMIZED and
+     UNAVAILABLE outputs are set accordingly.  */
+  virtual 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 = 0;
+
 protected:
   /* Architecture of the location.  */
   gdbarch *m_arch;
@@ -422,6 +473,14 @@ class dwarf_undefined final : public dwarf_location
   dwarf_undefined (gdbarch *arch)
     : dwarf_location (arch, 0)
   {}
+
+  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
+  {
+    *unavailable = 0;
+    *optimized = 1;
+  }
 };
 
 class dwarf_memory final : public dwarf_location
@@ -438,6 +497,11 @@ class dwarf_memory final : public dwarf_location
 
   dwarf_value_up to_value (struct type *type) const override;
 
+  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;
+
 private:
   /* True if the location belongs to a stack memory region.  */
   bool m_stack;
@@ -464,6 +528,46 @@ dwarf_memory::to_value (struct type *type) const
   return make_unique<dwarf_value> (m_offset, type);
 }
 
+void
+dwarf_memory::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
+{
+  LONGEST total_bits_to_skip = bits_to_skip;
+  CORE_ADDR start_address
+    = m_offset + (m_bit_suboffset + total_bits_to_skip) / HOST_CHAR_BIT;
+  gdb::byte_vector temp_buf;
+
+  *optimized = 0;
+  total_bits_to_skip += m_bit_suboffset;
+
+  if (total_bits_to_skip % HOST_CHAR_BIT == 0
+      && bit_size % HOST_CHAR_BIT == 0
+      && buf_bit_offset % HOST_CHAR_BIT == 0)
+    {
+      /* Everything is byte-aligned, no buffer needed.  */
+      read_from_memory (start_address,
+			buf + buf_bit_offset / HOST_CHAR_BIT,
+			bit_size / HOST_CHAR_BIT, m_stack, unavailable);
+    }
+  else
+    {
+      LONGEST this_size = bits_to_bytes (total_bits_to_skip, bit_size);
+      temp_buf.resize (this_size);
+
+      /* Can only read from memory on byte granularity so an
+	 additional buffer is required.  */
+      read_from_memory (start_address, temp_buf.data (), this_size,
+			m_stack, unavailable);
+
+      if (!*unavailable)
+	copy_bitwise (buf, buf_bit_offset, temp_buf.data (),
+		      total_bits_to_skip % HOST_CHAR_BIT,
+		      bit_size, big_endian);
+    }
+}
+
 /* Register location description entry.  */
 
 class dwarf_register final : public dwarf_location
@@ -473,11 +577,56 @@ class dwarf_register final : public dwarf_location
     : dwarf_location (arch, offset), m_regnum (regnum)
   {}
 
+  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;
+
 private:
   /* DWARF register number.  */
   unsigned int m_regnum;
 };
 
+void
+dwarf_register::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
+{
+  LONGEST total_bits_to_skip = bits_to_skip;
+  size_t read_bit_limit = location_bit_limit;
+  gdbarch *frame_arch = get_frame_arch (frame);
+  int reg = dwarf_reg_to_regnum_or_error (frame_arch, m_regnum);
+  ULONGEST reg_bits = HOST_CHAR_BIT * register_size (frame_arch, reg);
+  gdb::byte_vector temp_buf;
+
+  if (big_endian)
+    {
+      if (!read_bit_limit || reg_bits <= read_bit_limit)
+	read_bit_limit = bit_size;
+
+      total_bits_to_skip += reg_bits - (m_offset * HOST_CHAR_BIT
+					+ m_bit_suboffset + read_bit_limit);
+    }
+  else
+    total_bits_to_skip += m_offset * HOST_CHAR_BIT + m_bit_suboffset;
+
+  LONGEST this_size = bits_to_bytes (total_bits_to_skip, bit_size);
+  temp_buf.resize (this_size);
+
+  if (frame == nullptr)
+    internal_error (__FILE__, __LINE__, _("invalid frame information"));
+
+  /* Can only read from a register on byte granularity so an
+     additional buffer is required.  */
+  read_from_register (frame, reg, total_bits_to_skip / HOST_CHAR_BIT,
+		      temp_buf, optimized, unavailable);
+
+  /* Only copy data if valid.  */
+  if (!*optimized && !*unavailable)
+    copy_bitwise (buf, buf_bit_offset, temp_buf.data (),
+		  total_bits_to_skip % HOST_CHAR_BIT, bit_size, big_endian);
+}
+
 /* Implicit location description entry.  Describes a location
    description not found on the target but instead saved in a
    gdb-allocated buffer.  */
@@ -493,6 +642,10 @@ class dwarf_implicit final : public dwarf_location
       m_byte_order (byte_order)
   {}
 
+  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;
+
 private:
   /* Implicit location contents as a stream of bytes in target byte-order.  */
   gdb::byte_vector m_contents;
@@ -501,6 +654,45 @@ class dwarf_implicit final : public dwarf_location
   bfd_endian m_byte_order;
 };
 
+void
+dwarf_implicit::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
+{
+  ULONGEST implicit_bit_size = HOST_CHAR_BIT * m_contents.size ();
+  LONGEST total_bits_to_skip = bits_to_skip;
+  size_t read_bit_limit = location_bit_limit;
+
+  *optimized = 0;
+  *unavailable = 0;
+
+  /* Cut off at the end of the implicit value.  */
+  if (m_byte_order == BFD_ENDIAN_BIG)
+    {
+      if (!read_bit_limit || read_bit_limit > implicit_bit_size)
+	read_bit_limit = bit_size;
+
+      total_bits_to_skip
+	+= implicit_bit_size - (m_offset * HOST_CHAR_BIT
+			       + m_bit_suboffset + read_bit_limit);
+    }
+  else
+    total_bits_to_skip += m_offset * HOST_CHAR_BIT + m_bit_suboffset;
+
+  if (total_bits_to_skip >= implicit_bit_size)
+    {
+      *unavailable = 1;
+      return;
+    }
+
+  if (bit_size > implicit_bit_size - total_bits_to_skip)
+    bit_size = implicit_bit_size - total_bits_to_skip;
+
+  copy_bitwise (buf, buf_bit_offset, m_contents.data (),
+		total_bits_to_skip, bit_size, big_endian);
+}
+
 /* Implicit pointer location description entry.  */
 
 class dwarf_implicit_pointer final : public dwarf_location
@@ -516,6 +708,10 @@ class dwarf_implicit_pointer final : public dwarf_location
       m_addr_size (addr_size), m_die_offset (die_offset)
   {}
 
+  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;
+
 private:
   /* Per object file data of the implicit pointer.  */
   dwarf2_per_objfile *m_per_objfile;
@@ -530,6 +726,44 @@ class dwarf_implicit_pointer final : public dwarf_location
   sect_offset m_die_offset;
 };
 
+void
+dwarf_implicit_pointer::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
+{
+  frame_info *actual_frame = frame;
+  LONGEST total_bits_to_skip = bits_to_skip + m_bit_suboffset;
+
+  if (actual_frame == nullptr)
+    actual_frame = get_selected_frame (_("No frame selected."));
+
+  struct type *type
+    = address_type (get_frame_arch (actual_frame), m_addr_size);
+
+  struct value *value
+    = indirect_synthetic_pointer (m_die_offset, m_offset, m_per_cu,
+				  m_per_objfile, actual_frame, type);
+
+  gdb_byte *value_contents = value_contents_raw (value).data ()
+			     + total_bits_to_skip / HOST_CHAR_BIT;
+
+  if (total_bits_to_skip % HOST_CHAR_BIT == 0
+      && bit_size % HOST_CHAR_BIT == 0
+      && buf_bit_offset % HOST_CHAR_BIT == 0)
+    {
+      memcpy (buf + buf_bit_offset / HOST_CHAR_BIT,
+	      value_contents, bit_size / HOST_CHAR_BIT);
+    }
+  else
+    {
+      copy_bitwise (buf, buf_bit_offset, value_contents,
+		    total_bits_to_skip % HOST_CHAR_BIT,
+		    bit_size, big_endian);
+    }
+}
+
 /* Composite location description entry.  */
 
 class dwarf_composite final : public dwarf_location
@@ -545,6 +779,10 @@ class dwarf_composite final : public dwarf_location
     m_pieces.emplace_back (std::move (location), bit_size);
   }
 
+  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;
+
 private:
   /* Composite piece that contains a piece location
      description and it's size.  */
@@ -566,6 +804,50 @@ class dwarf_composite final : public dwarf_location
   std::vector<piece> m_pieces;
 };
 
+void
+dwarf_composite::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
+{
+  unsigned int pieces_num = m_pieces.size ();
+  LONGEST total_bits_to_skip = bits_to_skip;
+  unsigned int i;
+
+  total_bits_to_skip += m_offset * HOST_CHAR_BIT + m_bit_suboffset;
+
+  /* Skip pieces covered by the read offset.  */
+  for (i = 0; i < pieces_num; i++)
+    {
+      LONGEST piece_bit_size = m_pieces[i].size;
+
+      if (total_bits_to_skip < piece_bit_size)
+        break;
+
+      total_bits_to_skip -= piece_bit_size;
+    }
+
+  for (; i < pieces_num; i++)
+    {
+      LONGEST piece_bit_size = m_pieces[i].size;
+      LONGEST actual_bit_size = piece_bit_size;
+
+      if (actual_bit_size > bit_size)
+        actual_bit_size = bit_size;
+
+      m_pieces[i].location->read (frame, buf, buf_bit_offset,
+				  actual_bit_size, total_bits_to_skip,
+				  piece_bit_size, big_endian,
+				  optimized, unavailable);
+
+      if (bit_size == actual_bit_size || *optimized || *unavailable)
+	break;
+
+      buf_bit_offset += actual_bit_size;
+      bit_size -= actual_bit_size;
+    }
+}
+
 struct piece_closure
 {
   /* Reference count.  */
@@ -1181,27 +1463,8 @@ sect_variable_value (sect_offset sect_off,
 struct type *
 dwarf_expr_context::address_type () const
 {
-  gdbarch *arch = this->m_per_objfile->objfile->arch ();
-  dwarf_gdbarch_types *types
-    = (dwarf_gdbarch_types *) gdbarch_data (arch, dwarf_arch_cookie);
-  int ndx;
-
-  if (this->m_addr_size == 2)
-    ndx = 0;
-  else if (this->m_addr_size == 4)
-    ndx = 1;
-  else if (this->m_addr_size == 8)
-    ndx = 2;
-  else
-    error (_("Unsupported address size in DWARF expressions: %d bits"),
-	   8 * this->m_addr_size);
-
-  if (types->dw_types[ndx] == NULL)
-    types->dw_types[ndx]
-      = arch_integer_type (arch, 8 * this->m_addr_size,
-			   0, "<signed DWARF address type>");
-
-  return types->dw_types[ndx];
+  return ::address_type (this->m_per_objfile->objfile->arch (),
+			 this->m_addr_size);
 }
 
 /* Create a new context for the expression evaluator.  */
-- 
2.17.1


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

* [PATCH v4 07/28] Add write method to location description classes
  2021-11-05 11:38 [PATCH v4 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (5 preceding siblings ...)
  2021-11-05 11:38 ` [PATCH v4 06/28] Add read method to location description classes Zoran Zaric
@ 2021-11-05 11:38 ` Zoran Zaric
  2021-11-05 11:38 ` [PATCH v4 08/28] Add deref " Zoran Zaric
                   ` (20 subsequent siblings)
  27 siblings, 0 replies; 38+ messages in thread
From: Zoran Zaric @ 2021-11-05 11:38 UTC (permalink / raw)
  To: gdb-patches

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

After adding the interface for reading from the location, it also
makes sense to add the interface for writing.

To be clear, DWARF standard doesn't have a concept of writting to a
location, but because of the way how callback functions are used to
interact with the opaque implementation of the computed struct value
objects, the choice was to either use the existing DWARF entry classes
or to invent another way of representing the complexity behind those
computed objects.

Adding a write method seems to be a simpler option of the two.

gdb/ChangeLog:

        * dwarf2/expr.c (dwarf_location::write): New method.
        (dwarf_undefined::write): New method.
        (dwarf_memory::write): New method.
        (dwarf_register::write): New method.
        (dwarf_implicit::write): New method.
        (dwarf_implicit_pointer::write): New method.
        (dwarf_composite::write): New method.
---
 gdb/dwarf2/expr.c | 211 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 211 insertions(+)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index f2349208412..6129f4e8ec9 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -391,6 +391,28 @@ class dwarf_location : public dwarf_entry
 		     bool big_endian, int *optimized,
 		     int *unavailable) const = 0;
 
+  /* Write contents to a described location.
+
+     The write operation is performed in the context of a FRAME.
+     BIT_SIZE is the number of bits written.  The data written is
+     copied from the caller-managed BUF buffer.  BIG_ENDIAN defines an
+     endianness of the target.  BITS_TO_SKIP is a bit offset into the
+     location and BUF_BIT_OFFSET is buffer BUF's bit offset.
+     LOCATION_BIT_LIMIT is a maximum number of bits that location can
+     hold, where value zero signifies that there is no such
+     restriction.
+
+     Note that some location types can be written without a FRAME
+     context.
+
+     If the location is optimized out or unavailable, the OPTIMIZED and
+     UNAVAILABLE outputs are set.  */
+  virtual void write (frame_info *frame, const 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 = 0;
+
 protected:
   /* Architecture of the location.  */
   gdbarch *m_arch;
@@ -481,6 +503,14 @@ class dwarf_undefined final : public dwarf_location
     *unavailable = 0;
     *optimized = 1;
   }
+
+  void write (frame_info *frame, const 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
+  {
+    *unavailable = 0;
+    *optimized = 1;
+  }
 };
 
 class dwarf_memory final : public dwarf_location
@@ -502,6 +532,11 @@ class dwarf_memory final : public dwarf_location
 	     size_t location_bit_limit, bool big_endian,
 	     int *optimized, int *unavailable) const override;
 
+  void write (frame_info *frame, const 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;
+
 private:
   /* True if the location belongs to a stack memory region.  */
   bool m_stack;
@@ -568,6 +603,62 @@ dwarf_memory::read (frame_info *frame, gdb_byte *buf,
     }
 }
 
+void
+dwarf_memory::write (frame_info *frame, const 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
+{
+  LONGEST total_bits_to_skip = bits_to_skip;
+  CORE_ADDR start_address
+    = m_offset + (m_bit_suboffset + total_bits_to_skip) / HOST_CHAR_BIT;
+  gdb::byte_vector temp_buf;
+
+  *optimized = 0;
+  total_bits_to_skip += m_bit_suboffset;
+
+  if (total_bits_to_skip % HOST_CHAR_BIT == 0
+      && bit_size % HOST_CHAR_BIT == 0
+      && buf_bit_offset % HOST_CHAR_BIT == 0)
+    {
+      /* Everything is byte-aligned; no buffer needed.  */
+      write_to_memory (start_address, buf + buf_bit_offset / HOST_CHAR_BIT,
+		       bit_size / HOST_CHAR_BIT, m_stack, unavailable);
+    }
+  else
+    {
+      LONGEST this_size = bits_to_bytes (total_bits_to_skip, bit_size);
+      temp_buf.resize (this_size);
+
+      if (total_bits_to_skip % HOST_CHAR_BIT != 0
+	  || bit_size % HOST_CHAR_BIT != 0)
+	{
+	  if (this_size <= HOST_CHAR_BIT)
+	    /* Perform a single read for small sizes.  */
+	    read_from_memory (start_address, temp_buf.data (),
+			      this_size, m_stack, unavailable);
+	  else
+	    {
+	      /* Only the first and last bytes can possibly have
+		 any bits reused.  */
+	      read_from_memory (start_address, temp_buf.data (),
+				1, m_stack, unavailable);
+
+	      if (!*unavailable)
+		read_from_memory (start_address + this_size - 1,
+				  &temp_buf[this_size - 1], 1,
+				  m_stack, unavailable);
+	    }
+	}
+
+      copy_bitwise (temp_buf.data (), total_bits_to_skip % HOST_CHAR_BIT,
+		    buf, buf_bit_offset, bit_size, big_endian);
+
+      write_to_memory (start_address, temp_buf.data (), this_size,
+		       m_stack, unavailable);
+    }
+}
+
 /* Register location description entry.  */
 
 class dwarf_register final : public dwarf_location
@@ -581,6 +672,11 @@ class dwarf_register final : public dwarf_location
 	     size_t bit_size, LONGEST bits_to_skip, size_t location_bit_limit,
 	     bool big_endian, int *optimized, int *unavailable) const override;
 
+  void write (frame_info *frame, const 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;
+
 private:
   /* DWARF register number.  */
   unsigned int m_regnum;
@@ -627,6 +723,53 @@ dwarf_register::read (frame_info *frame, gdb_byte *buf,
 		  total_bits_to_skip % HOST_CHAR_BIT, bit_size, big_endian);
 }
 
+void
+dwarf_register::write (frame_info *frame, const 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
+{
+  LONGEST total_bits_to_skip = bits_to_skip;
+  size_t write_bit_limit = location_bit_limit;
+  gdbarch *frame_arch = get_frame_arch (frame);
+  int reg = dwarf_reg_to_regnum_or_error (frame_arch, m_regnum);
+  ULONGEST reg_bits = HOST_CHAR_BIT * register_size (frame_arch, reg);
+  gdb::byte_vector temp_buf;
+
+  if (frame == nullptr)
+    internal_error (__FILE__, __LINE__, _("invalid frame information"));
+
+  if (big_endian)
+    {
+      if (!write_bit_limit || reg_bits <= write_bit_limit)
+	write_bit_limit = bit_size;
+
+      total_bits_to_skip += reg_bits - (m_offset * HOST_CHAR_BIT
+					+ m_bit_suboffset + write_bit_limit);
+    }
+  else
+    total_bits_to_skip += m_offset * HOST_CHAR_BIT + m_bit_suboffset;
+
+  LONGEST this_size = bits_to_bytes (total_bits_to_skip, bit_size);
+  temp_buf.resize (this_size);
+
+  if (total_bits_to_skip % HOST_CHAR_BIT != 0
+      || bit_size % HOST_CHAR_BIT != 0)
+    {
+      /* Contents is copied non-byte-aligned into the register.
+         Need some bits from original register value.  */
+      read_from_register (frame, reg,
+			  total_bits_to_skip / HOST_CHAR_BIT,
+			  temp_buf, optimized, unavailable);
+    }
+
+  copy_bitwise (temp_buf.data (), total_bits_to_skip % HOST_CHAR_BIT, buf,
+		buf_bit_offset, bit_size, big_endian);
+
+  write_to_register (frame, reg, total_bits_to_skip / HOST_CHAR_BIT,
+		     temp_buf, optimized, unavailable);
+}
+
 /* Implicit location description entry.  Describes a location
    description not found on the target but instead saved in a
    gdb-allocated buffer.  */
@@ -646,6 +789,15 @@ class dwarf_implicit final : public dwarf_location
 	     size_t bit_size, LONGEST bits_to_skip, size_t location_bit_limit,
 	     bool big_endian, int *optimized, int *unavailable) const override;
 
+  void write (frame_info *frame, const 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
+  {
+    *optimized = 1;
+    *unavailable = 0;
+  }
+
 private:
   /* Implicit location contents as a stream of bytes in target byte-order.  */
   gdb::byte_vector m_contents;
@@ -712,6 +864,15 @@ class dwarf_implicit_pointer final : public dwarf_location
 	     size_t bit_size, LONGEST bits_to_skip, size_t location_bit_limit,
 	     bool big_endian, int *optimized, int *unavailable) const override;
 
+  void write (frame_info *frame, const 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
+  {
+    *optimized = 1;
+    *unavailable = 0;
+  }
+
 private:
   /* Per object file data of the implicit pointer.  */
   dwarf2_per_objfile *m_per_objfile;
@@ -783,6 +944,11 @@ class dwarf_composite final : public dwarf_location
 	     size_t bit_size, LONGEST bits_to_skip, size_t location_bit_limit,
 	     bool big_endian, int *optimized, int *unavailable) const override;
 
+  void write (frame_info *frame, const 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;
+
 private:
   /* Composite piece that contains a piece location
      description and it's size.  */
@@ -848,6 +1014,51 @@ dwarf_composite::read (frame_info *frame, gdb_byte *buf,
     }
 }
 
+void
+dwarf_composite::write (frame_info *frame, const 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
+{
+  LONGEST total_bits_to_skip = bits_to_skip;
+  unsigned int pieces_num = m_pieces.size ();
+  unsigned int i;
+
+  total_bits_to_skip += m_offset * HOST_CHAR_BIT + m_bit_suboffset;
+
+  /* Skip pieces covered by the write offset.  */
+  for (i = 0; i < pieces_num; i++)
+    {
+      LONGEST piece_bit_size = m_pieces[i].size;
+
+      if (total_bits_to_skip < piece_bit_size)
+	break;
+
+      total_bits_to_skip -= piece_bit_size;
+    }
+
+  for (; i < pieces_num; i++)
+    {
+      LONGEST piece_bit_size = m_pieces[i].size;
+      LONGEST actual_bit_size = piece_bit_size;
+
+      if (actual_bit_size > bit_size)
+        actual_bit_size = bit_size;
+
+      m_pieces[i].location->write (frame, buf, buf_bit_offset,
+				   actual_bit_size, total_bits_to_skip,
+				   piece_bit_size, big_endian,
+				   optimized, unavailable);
+
+      if (bit_size == actual_bit_size || *optimized || *unavailable)
+	break;
+
+      buf_bit_offset += actual_bit_size;
+      bit_size -= actual_bit_size;
+    }
+}
+
 struct piece_closure
 {
   /* Reference count.  */
-- 
2.17.1


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

* [PATCH v4 08/28] Add deref method to location description classes
  2021-11-05 11:38 [PATCH v4 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (6 preceding siblings ...)
  2021-11-05 11:38 ` [PATCH v4 07/28] Add write " Zoran Zaric
@ 2021-11-05 11:38 ` Zoran Zaric
  2021-11-05 11:38 ` [PATCH v4 09/28] Add read_from_gdb_value method to dwarf_location Zoran Zaric
                   ` (19 subsequent siblings)
  27 siblings, 0 replies; 38+ messages in thread
From: Zoran Zaric @ 2021-11-05 11:38 UTC (permalink / raw)
  To: gdb-patches

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

Concept of reading from a location seems to be too low level for the
DWARF standard. What the standard actually describes is a concept of
dereferencing, where the type of the operation result can be
specified in advance.

This can be seen in the definition of the DW_OP_derefX family of
expression operations, but it is also happening implicitly in the case
of DW_OP_fbreg, DW_OP_regval_type and DW_OP_bregX family of operations.

Currently, the DW_OP_derefX operations will take the value from the
DWARF expression stack and implicitly convert it to a memory location
description (in reality treat it as a memory address for a given
target) and apply the dereference operation to it. When we allow any
location description on a DWARF expression stack, these operations need
to work in the same way.

The conclusion here is that we need a universal method that models the
dereference operation for any class derived from a location description
class.

It is worth mentioning that because of how the passed in buffers are
currently being implemented, we needed a specialisation for the deref
method of the dwarf_memory class to support them.

gdb/ChangeLog:

        * dwarf2/expr.c (dwarf_location::deref): New method.
        (dwarf_memory::deref): New method.
---
 gdb/dwarf2/expr.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 123 insertions(+)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index 6129f4e8ec9..87a8b87eee7 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -413,6 +413,18 @@ class dwarf_location : public dwarf_entry
 		      bool big_endian, int *optimized,
 		      int *unavailable) const = 0;
 
+  /* Apply dereference operation on the DWARF location description.
+     Operation returns a DWARF value of a given TYPE type while FRAME
+     contains a frame context information of the location.  ADDR_INFO
+     (if present) describes a passed in memory buffer if a regular
+     memory read is not desired for certain address range.  If the SIZE
+     is specified, it must be equal or smaller than the TYPE type size.
+     If SIZE is smaller than the type size, the value will be zero
+     extended to the difference.  */
+  virtual std::unique_ptr<dwarf_value> deref
+    (frame_info *frame, const property_addr_info *addr_info,
+     struct type *type, size_t size = 0) const;
+
 protected:
   /* Architecture of the location.  */
   gdbarch *m_arch;
@@ -485,6 +497,43 @@ class dwarf_value final : public dwarf_entry
 
 using dwarf_value_up = std::unique_ptr<dwarf_value>;
 
+std::unique_ptr<dwarf_value>
+dwarf_location::deref (frame_info *frame, const property_addr_info *addr_info,
+		       struct type *type, size_t size) const
+{
+  bool big_endian = type_byte_order (type) == BFD_ENDIAN_BIG;
+  size_t actual_size = size != 0 ? size : TYPE_LENGTH (type);
+
+  if (actual_size > TYPE_LENGTH (type))
+    ill_formed_expression ();
+
+  /* If the size of the object read from memory is different
+     from the type length, we need to zero-extend it.  */
+  gdb::byte_vector read_buf (TYPE_LENGTH (type), 0);
+  gdb_byte *buf_ptr = read_buf.data ();
+  int optimized, unavailable;
+
+  if (big_endian)
+    buf_ptr += TYPE_LENGTH (type) - actual_size;
+
+  this->read (frame, buf_ptr, 0, actual_size * HOST_CHAR_BIT,
+	      0, 0, big_endian, &optimized, &unavailable);
+
+  if (optimized)
+    throw_error (OPTIMIZED_OUT_ERROR,
+		 _("Can't dereference "
+		   "update bitfield; containing word "
+		   "has been optimized out"));
+  if (unavailable)
+    throw_error (NOT_AVAILABLE_ERROR,
+		 _("Can't dereference "
+		   "update bitfield; containing word "
+		   "is unavailable"));
+
+  return make_unique<dwarf_value>
+    (gdb::array_view<const gdb_byte> (read_buf), type);
+}
+
 /* Undefined location description entry.  This is a special location
    description type that describes the location description that is
    not known.  */
@@ -537,6 +586,11 @@ class dwarf_memory final : public dwarf_location
 	      size_t location_bit_limit, bool big_endian,
 	      int *optimized, int *unavailable) const override;
 
+  std::unique_ptr<dwarf_value> deref (frame_info *frame,
+				      const property_addr_info *addr_info,
+				      struct type *type,
+				      size_t size = 0) const override;
+
 private:
   /* True if the location belongs to a stack memory region.  */
   bool m_stack;
@@ -659,6 +713,75 @@ dwarf_memory::write (frame_info *frame, const gdb_byte *buf,
     }
 }
 
+std::unique_ptr<dwarf_value>
+dwarf_memory::deref (frame_info *frame, const property_addr_info *addr_info,
+		     struct type *type, size_t size) const
+{
+  bool big_endian = type_byte_order (type) == BFD_ENDIAN_BIG;
+  size_t actual_size = size != 0 ? size : TYPE_LENGTH (type);
+
+  if (actual_size > TYPE_LENGTH (type))
+    ill_formed_expression ();
+
+  gdb::byte_vector read_buf (TYPE_LENGTH (type), 0);
+  size_t size_in_bits = actual_size * HOST_CHAR_BIT;
+  gdb_byte *buf_ptr = read_buf.data ();
+  bool passed_in_buf = false;
+
+  if (big_endian)
+    buf_ptr += TYPE_LENGTH (type) - actual_size;
+
+  /* Covers the case where we have a passed in memory that is not
+     part of the target and requires for the location description
+     to address it instead of addressing the actual target
+     memory.  */
+  LONGEST this_size = bits_to_bytes (m_bit_suboffset, size_in_bits);
+
+  /* We shouldn't have a case where we read from a passed in
+     memory and the same memory being marked as stack. */
+  if (!m_stack && this_size && addr_info != nullptr
+      && addr_info->valaddr.data () != nullptr)
+    {
+      CORE_ADDR offset = (CORE_ADDR) m_offset - addr_info->addr;
+
+      if (offset < addr_info->valaddr.size ()
+	  && offset + this_size <= addr_info->valaddr.size ())
+	{
+	  /* Using second buffer here because the copy_bitwise
+	     doesn't support in place copy.  */
+	  gdb::byte_vector temp_buf (this_size);
+
+	  memcpy (temp_buf.data (), addr_info->valaddr.data () + offset,
+		  this_size);
+	  copy_bitwise (buf_ptr, 0, temp_buf.data (),
+			m_bit_suboffset, size_in_bits, big_endian);
+	  passed_in_buf = true;
+	}
+    }
+
+  if (!passed_in_buf)
+    {
+      int optimized, unavailable;
+
+      this->read (frame, buf_ptr, 0, size_in_bits, 0, 0,
+		  big_endian, &optimized, &unavailable);
+
+      if (optimized)
+	throw_error (OPTIMIZED_OUT_ERROR,
+		     _("Can't dereference "
+		     "update bitfield; containing word "
+		     "has been optimized out"));
+      if (unavailable)
+	throw_error (NOT_AVAILABLE_ERROR,
+		     _("Can't dereference "
+		     "update bitfield; containing word "
+		     "is unavailable"));
+    }
+
+  return make_unique<dwarf_value>
+    (gdb::array_view<const gdb_byte> (read_buf), type);
+}
+
 /* Register location description entry.  */
 
 class dwarf_register final : public dwarf_location
-- 
2.17.1


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

* [PATCH v4 09/28] Add read_from_gdb_value method to dwarf_location
  2021-11-05 11:38 [PATCH v4 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (7 preceding siblings ...)
  2021-11-05 11:38 ` [PATCH v4 08/28] Add deref " Zoran Zaric
@ 2021-11-05 11:38 ` Zoran Zaric
  2021-11-05 11:38 ` [PATCH v4 10/28] Add write_to_gdb_value " Zoran Zaric
                   ` (18 subsequent siblings)
  27 siblings, 0 replies; 38+ messages in thread
From: Zoran Zaric @ 2021-11-05 11:38 UTC (permalink / raw)
  To: gdb-patches

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

The few patches are addressing the expectations of the existing
function calback interface of the computed struct value objects.

As mentioned in the previous patches the location description and the
interaction with that location are opaque to the struct value object,
but currently that interaction is influenced by the data contained
inside of that object and outside of the location description class.

Also, the struct value evaluation involves more then just writing or
reading the object contents buffer, in certain cases it is also
expected to throw an exception or mark different parts of the object
with additional information (optimized out bitmap for example).

As a result, reading the data from a struct value object and writing
that data into the location described, can be different then just
generic writing the data from a buffer (dwarf_location write method).

To make this distinction clear a new read_from_gdb_value method is
added to classes that derive from location description class.

gdb/ChangeLog:

        * dwarf2/expr.c (dwarf_location::read_from_gdb_value):
        New method.
        (dwarf_composite::read_from_gdb_value): New method.
---
 gdb/dwarf2/expr.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 99 insertions(+)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index 87a8b87eee7..e79d57fbfd4 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -425,6 +425,22 @@ class dwarf_location : public dwarf_entry
     (frame_info *frame, const property_addr_info *addr_info,
      struct type *type, size_t size = 0) const;
 
+/* Read data from the VALUE contents to the location specified by the
+   location description.
+
+   The read operation is performed in the context of a FRAME.  BIT_SIZE
+   is the number of bits to read.  VALUE_BIT_OFFSET is a bit offset
+   into a VALUE content and BITS_TO_SKIP is a bit offset into the
+   location.  LOCATION_BIT_LIMIT is a maximum number of bits that
+   location can hold, where value zero signifies that there is no such
+   restriction.
+
+   Note that some location types can be read without a FRAME context.  */
+  virtual void read_from_gdb_value (frame_info *frame, struct value *value,
+				    int value_bit_offset,
+				    LONGEST bits_to_skip, size_t bit_size,
+				    size_t location_bit_limit) const;
+
 protected:
   /* Architecture of the location.  */
   gdbarch *m_arch;
@@ -442,6 +458,31 @@ class dwarf_location : public dwarf_entry
 
 using dwarf_location_up = std::unique_ptr<dwarf_location>;
 
+void
+dwarf_location::read_from_gdb_value (frame_info *frame, struct value *value,
+				     int value_bit_offset,
+				     LONGEST bits_to_skip, size_t bit_size,
+				     size_t location_bit_limit) const
+{
+  int optimized, unavailable;
+  bool big_endian = type_byte_order (value_type (value)) == BFD_ENDIAN_BIG;
+
+  this->write (frame, value_contents (value).data (), value_bit_offset,
+	       bit_size, bits_to_skip, location_bit_limit,
+	       big_endian, &optimized, &unavailable);
+
+  if (optimized)
+    throw_error (OPTIMIZED_OUT_ERROR,
+		 _("Can't do read-modify-write to "
+		   "update bitfield; containing word "
+		   "has been optimized out"));
+  if (unavailable)
+    throw_error (NOT_AVAILABLE_ERROR,
+		 _("Can't do read-modify-write to "
+		   "update bitfield; containing word "
+		   "is unavailable"));
+}
+
 /* Value entry found on a DWARF expression evaluation stack.  */
 
 class dwarf_value final : public dwarf_entry
@@ -996,6 +1037,16 @@ class dwarf_implicit_pointer final : public dwarf_location
     *unavailable = 0;
   }
 
+  /* Reading from and writing to an implicit pointer is not meaningful,
+     so we just skip them here.  */
+  void read_from_gdb_value (frame_info *frame, struct value *value,
+			    int value_bit_offset,
+			    LONGEST bits_to_skip, size_t bit_size,
+			    size_t location_bit_limit) const override
+  {
+    mark_value_bits_optimized_out (value, bits_to_skip, bit_size);
+  }
+
 private:
   /* Per object file data of the implicit pointer.  */
   dwarf2_per_objfile *m_per_objfile;
@@ -1072,6 +1123,11 @@ class dwarf_composite final : public dwarf_location
 	      size_t location_bit_limit, bool big_endian,
 	      int *optimized, int *unavailable) const override;
 
+  void read_from_gdb_value (frame_info *frame, struct value *value,
+			    int value_bit_offset,
+			    LONGEST bits_to_skip, size_t bit_size,
+			    size_t location_bit_limit) const override;
+
 private:
   /* Composite piece that contains a piece location
      description and it's size.  */
@@ -1182,6 +1238,49 @@ dwarf_composite::write (frame_info *frame, const gdb_byte *buf,
     }
 }
 
+void
+dwarf_composite::read_from_gdb_value (frame_info *frame, struct value *value,
+				      int value_bit_offset,
+				      LONGEST bits_to_skip, size_t bit_size,
+				      size_t location_bit_limit) const
+{
+  ULONGEST total_bits_to_skip
+    = bits_to_skip + HOST_CHAR_BIT * m_offset + m_bit_suboffset;
+  ULONGEST remaining_bit_size = bit_size;
+  ULONGEST bit_offset = value_bit_offset;
+  unsigned int pieces_num = m_pieces.size ();
+  unsigned int i;
+
+  /* Advance to the first non-skipped piece.  */
+  for (i = 0; i < pieces_num; i++)
+    {
+      ULONGEST piece_bit_size = m_pieces[i].size;
+
+      if (total_bits_to_skip < piece_bit_size)
+	break;
+
+      total_bits_to_skip -= piece_bit_size;
+    }
+
+  for (; i < pieces_num; i++)
+    {
+      const dwarf_location &location = *m_pieces[i].location;
+      ULONGEST piece_bit_size = m_pieces[i].size;
+      size_t this_bit_size = piece_bit_size - total_bits_to_skip;
+
+      if (this_bit_size > remaining_bit_size)
+	this_bit_size = remaining_bit_size;
+
+      location.read_from_gdb_value (frame, value, bit_offset,
+				    total_bits_to_skip, this_bit_size,
+				    piece_bit_size);
+
+      bit_offset += this_bit_size;
+      remaining_bit_size -= this_bit_size;
+      total_bits_to_skip = 0;
+    }
+}
+
 struct piece_closure
 {
   /* Reference count.  */
-- 
2.17.1


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

* [PATCH v4 10/28] Add write_to_gdb_value method to dwarf_location
  2021-11-05 11:38 [PATCH v4 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (8 preceding siblings ...)
  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 ` Zoran Zaric
  2021-11-05 11:38 ` [PATCH v4 11/28] Add is_implicit_ptr_at " Zoran Zaric
                   ` (17 subsequent siblings)
  27 siblings, 0 replies; 38+ messages in thread
From: Zoran Zaric @ 2021-11-05 11:38 UTC (permalink / raw)
  To: gdb-patches

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

Similar story behind the previous read_from_gdb_value method applies
to the new write_to_gdb_value.

In the same way, reading the data from a location described and writing
that data to a struct value object, can be different from just generic
read the data from a buffer (location description read method).

To make this distinction clear, a new write_to_gdb_value method is
added to classes that derive from location description class.

gdb/ChangeLog:

        * dwarf2/expr.c (dwarf_location::write_to_gdb_value):
        New method.
        (dwarf_composite::write_to_gdb_value): New method.
---
 gdb/dwarf2/expr.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 89 insertions(+)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index e79d57fbfd4..b2fb0099b0e 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -441,6 +441,22 @@ class dwarf_location : public dwarf_entry
 				    LONGEST bits_to_skip, size_t bit_size,
 				    size_t location_bit_limit) const;
 
+/* Write data to the VALUE contents from the location specified by the
+   location description.
+
+   The write operation is performed in the context of a FRAME.
+   BIT_SIZE is the number of bits to read.  VALUE_BIT_OFFSET is a bit
+   offset into a VALUE content and BITS_TO_SKIP is a bit offset into
+   the location.  LOCATION_BIT_LIMIT is a maximum number of bits that
+   location can hold, where value zero signifies that there is no such
+   restriction.
+
+   Note that some location types can be read without a FRAME context.  */
+  virtual void write_to_gdb_value (frame_info *frame, struct value *value,
+				   int value_bit_offset,
+				   LONGEST bits_to_skip, size_t bit_size,
+				   size_t location_bit_limit) const;
+
 protected:
   /* Architecture of the location.  */
   gdbarch *m_arch;
@@ -483,6 +499,25 @@ dwarf_location::read_from_gdb_value (frame_info *frame, struct value *value,
 		   "is unavailable"));
 }
 
+void
+dwarf_location::write_to_gdb_value (frame_info *frame, struct value *value,
+				    int value_bit_offset,
+				    LONGEST bits_to_skip, size_t bit_size,
+				    size_t location_bit_limit) const
+{
+  int optimized, unavailable;
+  bool big_endian = type_byte_order (value_type (value)) == BFD_ENDIAN_BIG;
+
+  this->read (frame, value_contents_raw (value).data (), value_bit_offset,
+	      bit_size, bits_to_skip, location_bit_limit,
+	      big_endian, &optimized, &unavailable);
+
+  if (optimized)
+    mark_value_bits_optimized_out (value, value_bit_offset, bit_size);
+  if (unavailable)
+    mark_value_bits_unavailable (value, value_bit_offset, bit_size);
+}
+
 /* Value entry found on a DWARF expression evaluation stack.  */
 
 class dwarf_value final : public dwarf_entry
@@ -1047,6 +1082,12 @@ class dwarf_implicit_pointer final : public dwarf_location
     mark_value_bits_optimized_out (value, bits_to_skip, bit_size);
   }
 
+  void write_to_gdb_value (frame_info *frame, struct value *value,
+			   int value_bit_offset,
+			   LONGEST bits_to_skip, size_t bit_size,
+			   size_t location_bit_limit) const override
+  {}
+
 private:
   /* Per object file data of the implicit pointer.  */
   dwarf2_per_objfile *m_per_objfile;
@@ -1128,6 +1169,11 @@ class dwarf_composite final : public dwarf_location
 			    LONGEST bits_to_skip, size_t bit_size,
 			    size_t location_bit_limit) const override;
 
+  void write_to_gdb_value (frame_info *frame, struct value *value,
+			   int value_bit_offset,
+			   LONGEST bits_to_skip, size_t bit_size,
+			   size_t location_bit_limit) const override;
+
 private:
   /* Composite piece that contains a piece location
      description and it's size.  */
@@ -1281,6 +1327,49 @@ dwarf_composite::read_from_gdb_value (frame_info *frame, struct value *value,
     }
 }
 
+void
+dwarf_composite::write_to_gdb_value (frame_info *frame, struct value *value,
+				     int value_bit_offset,
+				     LONGEST bits_to_skip, size_t bit_size,
+				     size_t location_bit_limit) const
+{
+  ULONGEST total_bits_to_skip
+    = bits_to_skip + HOST_CHAR_BIT * m_offset + m_bit_suboffset;
+  ULONGEST remaining_bit_size = bit_size;
+  ULONGEST bit_offset = value_bit_offset;
+  unsigned int pieces_num = m_pieces.size ();
+  unsigned int i;
+
+  /* Advance to the first non-skipped piece.  */
+  for (i = 0; i < pieces_num; i++)
+    {
+      ULONGEST piece_bit_size = m_pieces[i].size;
+
+      if (total_bits_to_skip < piece_bit_size)
+	break;
+
+      total_bits_to_skip -= piece_bit_size;
+    }
+
+  for (; i < pieces_num; i++)
+    {
+      const dwarf_location &location = *m_pieces[i].location;
+      ULONGEST piece_bit_size = m_pieces[i].size;
+      size_t this_bit_size = piece_bit_size - total_bits_to_skip;
+
+      if (this_bit_size > remaining_bit_size)
+	this_bit_size = remaining_bit_size;
+
+      location.write_to_gdb_value (frame, value, bit_offset,
+				   total_bits_to_skip, this_bit_size,
+				   piece_bit_size);
+
+      bit_offset += this_bit_size;
+      remaining_bit_size -= this_bit_size;
+      total_bits_to_skip = 0;
+    }
+}
+
 struct piece_closure
 {
   /* Reference count.  */
-- 
2.17.1


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

* [PATCH v4 11/28] Add is_implicit_ptr_at method to dwarf_location
  2021-11-05 11:38 [PATCH v4 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (9 preceding siblings ...)
  2021-11-05 11:38 ` [PATCH v4 10/28] Add write_to_gdb_value " Zoran Zaric
@ 2021-11-05 11:38 ` Zoran Zaric
  2021-11-05 11:38 ` [PATCH v4 12/28] Add indirect_implicit_ptr to dwarf_location class Zoran Zaric
                   ` (16 subsequent siblings)
  27 siblings, 0 replies; 38+ messages in thread
From: Zoran Zaric @ 2021-11-05 11:38 UTC (permalink / raw)
  To: gdb-patches

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

Another expectation of the existing function callback interface of the
computed struct value is to check if a specific part (on a given offset
of a given length) of an underlying location description is an implicit
pointer location description.

To satisfy this expectation a new is_implicit_ptr_at has been added.

gdb/ChangeLog:

        * dwarf2/expr.c (dwarf_location::is_implicit_ptr_at):
        New method.
        (dwarf_implicit_pointer::is_implicit_ptr_at): New method.
        (dwarf_composite::is_implicit_ptr_at): New method.
---
 gdb/dwarf2/expr.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index b2fb0099b0e..a933ca2797d 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -457,6 +457,14 @@ class dwarf_location : public dwarf_entry
 				   LONGEST bits_to_skip, size_t bit_size,
 				   size_t location_bit_limit) const;
 
+  /* Check if a given DWARF location description contains an implicit
+     pointer location description of a BIT_LENGTH size on a given
+     BIT_OFFSET offset.  */
+  virtual bool is_implicit_ptr_at (LONGEST bit_offset, int bit_length) const
+  {
+     return false;
+  }
+
 protected:
   /* Architecture of the location.  */
   gdbarch *m_arch;
@@ -1088,6 +1096,11 @@ class dwarf_implicit_pointer final : public dwarf_location
 			   size_t location_bit_limit) const override
   {}
 
+  bool is_implicit_ptr_at (LONGEST bit_offset, int bit_length) const override
+  {
+     return true;
+  }
+
 private:
   /* Per object file data of the implicit pointer.  */
   dwarf2_per_objfile *m_per_objfile;
@@ -1174,6 +1187,8 @@ class dwarf_composite final : public dwarf_location
 			   LONGEST bits_to_skip, size_t bit_size,
 			   size_t location_bit_limit) const override;
 
+  bool is_implicit_ptr_at (LONGEST bit_offset, int bit_length) const override;
+
 private:
   /* Composite piece that contains a piece location
      description and it's size.  */
@@ -1370,6 +1385,43 @@ dwarf_composite::write_to_gdb_value (frame_info *frame, struct value *value,
     }
 }
 
+bool
+dwarf_composite::is_implicit_ptr_at (LONGEST bit_offset, int bit_length) const
+{
+  /* Advance to the first non-skipped piece.  */
+  unsigned int pieces_num = m_pieces.size ();
+  LONGEST total_bit_offset = bit_offset;
+  LONGEST total_bit_length = bit_length;
+
+  total_bit_offset += HOST_CHAR_BIT * m_offset + m_bit_suboffset;
+
+  for (unsigned int i = 0; i < pieces_num && total_bit_length != 0; i++)
+    {
+      const piece &piece = m_pieces[i];
+      ULONGEST read_bit_length = piece.size;
+
+      if (total_bit_offset >= read_bit_length)
+	{
+	  total_bit_offset -= read_bit_length;
+	  continue;
+	}
+
+      read_bit_length -= total_bit_offset;
+
+      if (total_bit_length < read_bit_length)
+	read_bit_length = total_bit_length;
+
+      if (piece.location->is_implicit_ptr_at (total_bit_offset,
+					      read_bit_length))
+	return true;
+
+      total_bit_offset = 0;
+      total_bit_length -= read_bit_length;
+    }
+
+    return false;
+}
+
 struct piece_closure
 {
   /* Reference count.  */
-- 
2.17.1


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

* [PATCH v4 12/28] Add indirect_implicit_ptr to dwarf_location class
  2021-11-05 11:38 [PATCH v4 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (10 preceding siblings ...)
  2021-11-05 11:38 ` [PATCH v4 11/28] Add is_implicit_ptr_at " Zoran Zaric
@ 2021-11-05 11:38 ` Zoran Zaric
  2021-11-05 11:38 ` [PATCH v4 13/28] Add is_optimized_out " Zoran Zaric
                   ` (15 subsequent siblings)
  27 siblings, 0 replies; 38+ messages in thread
From: Zoran Zaric @ 2021-11-05 11:38 UTC (permalink / raw)
  To: gdb-patches

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

Similarly to the is_implicit_ptr_at method, the existing function
callback interface of the computed struct value, requiers a way to
apply indirection to an implicit pointer on a given offset of a given
length of an underlying location description.

This is different than reading from a struct value object (previously
described write_to_gdb_value method) in a way that the result of this
operation is expected to be a struct value of a pointed source level
variable instead of reading the value of that variable.

In the same way this is also different operation than the deref method
because the deref returns a read value of a given type from that
location description.

gdb/ChangeLog:

        * dwarf2/expr.c (dwarf_location::indirect_implicit_ptr):
        New method.
        (dwarf_implicit_pointer::indirect_implicit_ptr): New method.
        (dwarf_composite::indirect_implicit_ptr): New method.
---
 gdb/dwarf2/expr.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index a933ca2797d..185324f1d2d 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -465,6 +465,24 @@ class dwarf_location : public dwarf_entry
      return false;
   }
 
+  /* Recursive indirecting of the implicit pointer location description
+     if that location is or encapsulates an implicit pointer.  The
+     operation is performed in a given FRAME context, using the TYPE as
+     the type of the pointer.  Where POINTER_OFFSET is an offset
+     applied to that implicit pointer location description before the
+     operation.  BIT_OFFSET is a bit offset applied to the location and
+     BIT_LENGTH is a bit length of the read.
+
+     Indirecting is only performed on the implicit pointer location
+     description parts of the location.  */
+  virtual value *indirect_implicit_ptr (frame_info *frame, struct type *type,
+					LONGEST pointer_offset = 0,
+					LONGEST bit_offset = 0,
+					int bit_length = 0) const
+  {
+    return nullptr;
+  }
+
 protected:
   /* Architecture of the location.  */
   gdbarch *m_arch;
@@ -1101,6 +1119,11 @@ class dwarf_implicit_pointer final : public dwarf_location
      return true;
   }
 
+  value *indirect_implicit_ptr (frame_info *frame, struct type *type,
+				LONGEST pointer_offset = 0,
+				LONGEST bit_offset = 0,
+				int bit_length = 0) const override;
+
 private:
   /* Per object file data of the implicit pointer.  */
   dwarf2_per_objfile *m_per_objfile;
@@ -1153,6 +1176,17 @@ dwarf_implicit_pointer::read (frame_info *frame, gdb_byte *buf,
     }
 }
 
+value *
+dwarf_implicit_pointer::indirect_implicit_ptr (frame_info *frame,
+					       struct type *type,
+					       LONGEST pointer_offset,
+					       LONGEST bit_offset,
+					       int bit_length) const
+{
+  return indirect_synthetic_pointer (m_die_offset, m_offset + pointer_offset,
+				     m_per_cu, m_per_objfile, frame, type);
+}
+
 /* Composite location description entry.  */
 
 class dwarf_composite final : public dwarf_location
@@ -1189,6 +1223,11 @@ class dwarf_composite final : public dwarf_location
 
   bool is_implicit_ptr_at (LONGEST bit_offset, int bit_length) const override;
 
+  value *indirect_implicit_ptr (frame_info *frame, struct type *type,
+				LONGEST pointer_offset = 0,
+				LONGEST bit_offset = 0,
+				int bit_length = 0) const override;
+
 private:
   /* Composite piece that contains a piece location
      description and it's size.  */
@@ -1422,6 +1461,40 @@ dwarf_composite::is_implicit_ptr_at (LONGEST bit_offset, int bit_length) const
     return false;
 }
 
+value *
+dwarf_composite::indirect_implicit_ptr (frame_info *frame, struct type *type,
+					LONGEST pointer_offset,
+					LONGEST bit_offset,
+					int bit_length) const
+{
+  LONGEST total_bit_offset = HOST_CHAR_BIT * m_offset
+			     + m_bit_suboffset + bit_offset;
+
+  /* Advance to the first non-skipped piece.  */
+  for (const piece &piece : m_pieces)
+    {
+      ULONGEST read_bit_length = piece.size;
+
+      if (total_bit_offset >= read_bit_length)
+	{
+	  total_bit_offset -= read_bit_length;
+	  continue;
+	}
+
+      read_bit_length -= total_bit_offset;
+
+      if (bit_length < read_bit_length)
+	read_bit_length = bit_length;
+
+      return piece.location->indirect_implicit_ptr (frame, type,
+						    pointer_offset,
+						    total_bit_offset,
+						    read_bit_length);
+    }
+
+  return nullptr;
+}
+
 struct piece_closure
 {
   /* Reference count.  */
-- 
2.17.1


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

* [PATCH v4 13/28] Add is_optimized_out to dwarf_location class
  2021-11-05 11:38 [PATCH v4 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (11 preceding siblings ...)
  2021-11-05 11:38 ` [PATCH v4 12/28] Add indirect_implicit_ptr to dwarf_location class Zoran Zaric
@ 2021-11-05 11:38 ` Zoran Zaric
  2021-11-05 11:38 ` [PATCH v4 14/28] Add new computed struct value callback interface Zoran Zaric
                   ` (14 subsequent siblings)
  27 siblings, 0 replies; 38+ messages in thread
From: Zoran Zaric @ 2021-11-05 11:38 UTC (permalink / raw)
  To: gdb-patches

Similarly to the is_implicit_ptr_at method, the existing function
callback interface of the computed struct value, requiers a way to
check if the underlying location description describes any part as
optimized out.

gdb/ChangeLog:

        * dwarf2/expr.c (dwarf_location::is_optimized_out):
        New method.
        (dwarf_implicit::is_optimized_out): New method.
        (dwarf_register::is_optimized_out): New method.
        (dwarf_composite::is_optimized_out): New method.
---
 gdb/dwarf2/expr.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 97 insertions(+)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index 185324f1d2d..a16c53377b7 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -483,6 +483,21 @@ class dwarf_location : public dwarf_entry
     return nullptr;
   }
 
+  /* Check if location description resolves into optimized out.
+
+     The check operation is performed in the context of a FRAME.
+     BIG_ENDIAN defines the endianness of the target, BIT_SIZE is the
+     number of bits to read and BITS_TO_SKIP is a bit offset into the
+     location.  LOCATION_BIT_LIMIT is a maximum number of bits that
+     location can hold, where value zero signifies that there is
+     no such restriction.  */
+  virtual bool is_optimized_out (frame_info *frame, bool big_endian,
+				 LONGEST bits_to_skip, size_t bit_size,
+				 size_t location_bit_limit) const
+  {
+    return false;
+  }
+
 protected:
   /* Architecture of the location.  */
   gdbarch *m_arch;
@@ -662,6 +677,13 @@ class dwarf_undefined final : public dwarf_location
     *unavailable = 0;
     *optimized = 1;
   }
+
+  bool is_optimized_out (frame_info *frame, bool big_endian,
+			 LONGEST bits_to_skip, size_t bit_size,
+			 size_t location_bit_limit) const override
+  {
+    return true;
+  }
 };
 
 class dwarf_memory final : public dwarf_location
@@ -902,6 +924,10 @@ class dwarf_register final : public dwarf_location
 	      size_t location_bit_limit, bool big_endian,
 	      int *optimized, int *unavailable) const override;
 
+  bool is_optimized_out (frame_info *frame, bool big_endian,
+			 LONGEST bits_to_skip, size_t bit_size,
+			 size_t location_bit_limit) const override;
+
 private:
   /* DWARF register number.  */
   unsigned int m_regnum;
@@ -995,6 +1021,24 @@ dwarf_register::write (frame_info *frame, const gdb_byte *buf,
 		     temp_buf, optimized, unavailable);
 }
 
+bool
+dwarf_register::is_optimized_out (frame_info *frame, bool big_endian,
+				  LONGEST bits_to_skip, size_t bit_size,
+				  size_t location_bit_limit) const
+{
+  int optimized, unavailable;
+  gdb::byte_vector temp_buf (bit_size);
+
+  this->read (frame, temp_buf.data (), 0, bit_size,
+	      bits_to_skip, location_bit_limit,
+	      big_endian, &optimized, &unavailable);
+
+  if (optimized)
+    return true;
+
+  return false;
+}
+
 /* Implicit location description entry.  Describes a location
    description not found on the target but instead saved in a
    gdb-allocated buffer.  */
@@ -1023,6 +1067,13 @@ class dwarf_implicit final : public dwarf_location
     *unavailable = 0;
   }
 
+  bool is_optimized_out (frame_info *frame, bool big_endian,
+			 LONGEST bits_to_skip, size_t bit_size,
+			 size_t location_bit_limit) const override
+  {
+    return true;
+  }
+
 private:
   /* Implicit location contents as a stream of bytes in target byte-order.  */
   gdb::byte_vector m_contents;
@@ -1228,6 +1279,10 @@ class dwarf_composite final : public dwarf_location
 				LONGEST bit_offset = 0,
 				int bit_length = 0) const override;
 
+  bool is_optimized_out (frame_info *frame, bool big_endian,
+			 LONGEST bits_to_skip, size_t bit_size,
+			 size_t location_bit_limit) const override;
+
 private:
   /* Composite piece that contains a piece location
      description and it's size.  */
@@ -1495,6 +1550,48 @@ dwarf_composite::indirect_implicit_ptr (frame_info *frame, struct type *type,
   return nullptr;
 }
 
+bool
+dwarf_composite::is_optimized_out (frame_info *frame, bool big_endian,
+				   LONGEST bits_to_skip, size_t bit_size,
+				   size_t location_bit_limit) const
+{
+  ULONGEST total_bits_to_skip
+    = bits_to_skip + HOST_CHAR_BIT * m_offset + m_bit_suboffset;
+  ULONGEST remaining_bit_size = bit_size;
+  unsigned int pieces_num = m_pieces.size ();
+  unsigned int i;
+
+  /* Advance to the first non-skipped piece.  */
+  for (i = 0; i < pieces_num; i++)
+    {
+      ULONGEST piece_bit_size = m_pieces[i].size;
+
+      if (total_bits_to_skip < piece_bit_size)
+	break;
+
+      total_bits_to_skip -= piece_bit_size;
+    }
+
+  for (; i < pieces_num; i++)
+    {
+      const dwarf_location &location = *m_pieces[i].location;
+      ULONGEST piece_bit_size = m_pieces[i].size;
+      size_t this_bit_size = piece_bit_size - total_bits_to_skip;
+
+      if (this_bit_size > remaining_bit_size)
+	this_bit_size = remaining_bit_size;
+
+      if (location.is_optimized_out (frame, big_endian, total_bits_to_skip,
+				     this_bit_size, piece_bit_size))
+	return true;
+
+      remaining_bit_size -= this_bit_size;
+      total_bits_to_skip = 0;
+    }
+
+  return false;
+}
+
 struct piece_closure
 {
   /* Reference count.  */
-- 
2.17.1


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

* [PATCH v4 14/28] Add new computed struct value callback interface
  2021-11-05 11:38 [PATCH v4 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (12 preceding siblings ...)
  2021-11-05 11:38 ` [PATCH v4 13/28] Add is_optimized_out " Zoran Zaric
@ 2021-11-05 11:38 ` Zoran Zaric
  2021-11-05 11:38 ` [PATCH v4 15/28] Add to_gdb_value method to DWARF entry class Zoran Zaric
                   ` (13 subsequent siblings)
  27 siblings, 0 replies; 38+ messages in thread
From: Zoran Zaric @ 2021-11-05 11:38 UTC (permalink / raw)
  To: gdb-patches

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

At this point all support is there to add a new callback interface
for the computed struct value infrastructure.

Original callback interface (piece closure) is going to be removed as
soon as the switch to the new DWARF entry classes is done in the next
few patches.

gdb/ChangeLog:

        * dwarf2/expr.c (class computed_closure): New class.
        (closure_value_funcs): New closure callback structure.
        (copy_value_closure): New function.
        (free_value_closure): New function.
        (rw_closure_value): New function.
        (check_synthetic_pointer): New function.
        (write_closure_value): New function.
        (read_closure_value): New function.
        (is_optimized_out_closure_value): New function.
        (indirect_closure_value): New function.
        (coerce_closure_ref): New function.
---
 gdb/dwarf2/expr.c | 324 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 324 insertions(+)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index a16c53377b7..d76dddab643 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -312,6 +312,96 @@ address_type (gdbarch *arch, int addr_size)
 class dwarf_location;
 class dwarf_value;
 
+/* Closure callback functions.  */
+
+static void *
+copy_value_closure (const value *v);
+
+static void
+free_value_closure (value *v);
+
+static void
+rw_closure_value (value *v, value *from);
+
+static int
+check_synthetic_pointer (const value *value, LONGEST bit_offset,
+			 int bit_length);
+
+static void
+write_closure_value (value *to, value *from);
+
+static void
+read_closure_value (value *v);
+
+static bool
+is_optimized_out_closure_value (value *v);
+
+static value *
+indirect_closure_value (value *value);
+
+static value *
+coerce_closure_ref (const value *value);
+
+/* Functions for accessing a variable described by DW_OP_piece,
+   DW_OP_bit_piece or DW_OP_implicit_pointer.  */
+
+static const lval_funcs closure_value_funcs = {
+  read_closure_value,
+  write_closure_value,
+  is_optimized_out_closure_value,
+  indirect_closure_value,
+  coerce_closure_ref,
+  check_synthetic_pointer,
+  copy_value_closure,
+  free_value_closure
+};
+
+/* Closure class that encapsulates a DWARF location description and a
+   frame information used when that location description was created.
+   Used for lval_computed value abstraction.  */
+
+class computed_closure : public refcounted_object
+{
+public:
+  computed_closure (std::unique_ptr<dwarf_location> location,
+		    struct frame_id frame_id)
+    : m_location (std::move (location)), m_frame_id (frame_id)
+  {}
+
+  computed_closure (std::unique_ptr<dwarf_location> location,
+		    struct frame_info *frame)
+    : m_location (std::move (location)), m_frame (frame)
+  {}
+
+  const dwarf_location &get_location () const
+  {
+    return *m_location;
+  }
+
+  frame_id get_frame_id () const
+  {
+    gdb_assert (m_frame == nullptr);
+    return m_frame_id;
+  }
+
+  frame_info *get_frame () const
+  {
+    return m_frame;
+  }
+
+private:
+  /* Entry that this class encloses.  */
+  const std::unique_ptr<const dwarf_location> m_location;
+
+  /* Frame ID context of the closure.  */
+  frame_id m_frame_id;
+
+  /* In the case of frame expression evaluator the frame_id
+     is not safe to use because the frame itself is being built.
+     Only in these cases we set and use frame info directly.  */
+  frame_info *m_frame = nullptr;
+};
+
 /* Base class that describes entries found on a DWARF expression
    evaluation stack.  */
 
@@ -1592,6 +1682,240 @@ dwarf_composite::is_optimized_out (frame_info *frame, bool big_endian,
   return false;
 }
 
+static void *
+copy_value_closure (const value *v)
+{
+  computed_closure *closure = ((computed_closure*) value_computed_closure (v));
+
+  if (closure == nullptr)
+    internal_error (__FILE__, __LINE__, _("invalid closure type"));
+
+  closure->incref ();
+  return closure;
+}
+
+static void
+free_value_closure (value *v)
+{
+  computed_closure *closure = ((computed_closure*) value_computed_closure (v));
+
+  if (closure == nullptr)
+    internal_error (__FILE__, __LINE__, _("invalid closure type"));
+
+  closure->decref ();
+
+  if (closure->refcount () == 0)
+    delete closure;
+}
+
+/* Read or write a closure value V.  If FROM != NULL, operate in "write
+   mode": copy FROM into the closure comprising V.  If FROM == NULL,
+   operate in "read mode": fetch the contents of the (lazy) value V by
+   composing it from its closure.  */
+
+static void
+rw_closure_value (value *v, value *from)
+{
+  LONGEST bit_offset = 0, max_bit_size;
+  computed_closure *closure = (computed_closure*) value_computed_closure (v);
+  struct type *v_type = value_type (v);
+  bool big_endian = type_byte_order (v_type) == BFD_ENDIAN_BIG;
+  const dwarf_location &location = closure->get_location ();
+  /* 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 (v_type->arch ());
+
+  if (from == nullptr)
+    {
+      if (v_type != value_enclosing_type (v))
+        internal_error (__FILE__, __LINE__,
+			_("Should not be able to create a lazy value with "
+			  "an enclosing type"));
+    }
+
+  ULONGEST bits_to_skip = HOST_CHAR_BIT * unit_size * value_offset (v);
+
+  /* If there are bits that don't complete a byte, count them in.  */
+  if (value_bitsize (v))
+    {
+      bits_to_skip
+	+= HOST_CHAR_BIT * unit_size * value_offset (value_parent (v))
+	   + value_bitpos (v);
+      if (from != nullptr && big_endian)
+	{
+	  /* Use the least significant bits of FROM.  */
+	  max_bit_size = HOST_CHAR_BIT * TYPE_LENGTH (value_type (from));
+	  bit_offset = max_bit_size - value_bitsize (v);
+	}
+      else
+	max_bit_size = value_bitsize (v);
+    }
+  else
+    max_bit_size = HOST_CHAR_BIT * TYPE_LENGTH (v_type);
+
+  frame_info *frame = closure->get_frame ();
+
+  if (frame == nullptr)
+    frame = frame_find_by_id (closure->get_frame_id ());
+
+  if (from == nullptr)
+    {
+      location.write_to_gdb_value (frame, v, bit_offset, bits_to_skip,
+				   max_bit_size - bit_offset, 0);
+    }
+  else
+    {
+      location.read_from_gdb_value (frame, from, bit_offset, bits_to_skip,
+				    max_bit_size - bit_offset, 0);
+    }
+}
+
+static void
+read_closure_value (value *v)
+{
+  rw_closure_value (v, NULL);
+}
+
+static void
+write_closure_value (value *to, value *from)
+{
+  rw_closure_value (to, from);
+}
+
+/* Check if a closure value V describes any piece of the
+   underlying location description as optimized out.  */
+
+static bool
+is_optimized_out_closure_value (value *v)
+{
+  LONGEST max_bit_size;
+  computed_closure *closure = (computed_closure*) value_computed_closure (v);
+  struct type *v_type = value_type (v);
+  bool big_endian = type_byte_order (v_type) == BFD_ENDIAN_BIG;
+  const dwarf_location &location = closure->get_location ();
+  /* 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 (v_type->arch ());
+
+  if (v_type != value_enclosing_type (v))
+    internal_error (__FILE__, __LINE__,
+		    _("Should not be able to create a lazy value with "
+		      "an enclosing type"));
+
+  ULONGEST bits_to_skip = HOST_CHAR_BIT * unit_size * value_offset (v);
+
+  /* If there are bits that don't complete a byte, count them in.  */
+  if (value_bitsize (v))
+    {
+      bits_to_skip
+	+= HOST_CHAR_BIT * unit_size * value_offset (value_parent (v))
+	   + value_bitpos (v);
+      max_bit_size = value_bitsize (v);
+    }
+  else
+    max_bit_size = HOST_CHAR_BIT * TYPE_LENGTH (v_type);
+
+  frame_info *frame = closure->get_frame ();
+
+  if (frame == nullptr)
+    frame = frame_find_by_id (closure->get_frame_id ());
+
+  return location.is_optimized_out (frame, big_endian, bits_to_skip,
+				    max_bit_size, 0);
+}
+
+/* An implementation of an lval_funcs method to see whether a value is
+   a synthetic pointer.  */
+
+static int
+check_synthetic_pointer (const value *value, LONGEST bit_offset,
+			 int bit_length)
+{
+  /* 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 (value_type (value)->arch ());
+  LONGEST total_bit_offset
+    = HOST_CHAR_BIT * unit_size * value_offset (value) + bit_offset;
+
+  if (value_bitsize (value))
+    total_bit_offset += value_bitpos (value);
+
+  computed_closure *closure
+    = (computed_closure *) value_computed_closure (value);
+
+  return closure->get_location ().is_implicit_ptr_at (total_bit_offset,
+						      bit_length);
+}
+
+/* An implementation of an lval_funcs method to indirect through a
+   pointer.  This handles the synthetic pointer case when needed.  */
+
+static value *
+indirect_closure_value (value *value)
+{
+  computed_closure *closure
+    = (computed_closure *) value_computed_closure (value);
+
+  struct type *type = check_typedef (value_type (value));
+  if (type->code () != TYPE_CODE_PTR)
+    return nullptr;
+
+  /* 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 (type->arch ());
+  LONGEST bit_length = HOST_CHAR_BIT * TYPE_LENGTH (type);
+  LONGEST bit_offset = HOST_CHAR_BIT * unit_size * value_offset (value);
+
+  if (value_bitsize (value))
+    bit_offset += value_bitpos (value);
+
+  frame_info *frame = get_selected_frame (_("No frame selected."));
+
+  /* This is an offset requested by GDB, such as value subscripts.
+     However, due to how synthetic pointers are implemented, this is
+     always presented to us as a pointer type.  This means we have to
+     sign-extend it manually as appropriate.  Use raw
+     extract_signed_integer directly rather than value_as_address and
+     sign extend afterwards on architectures that would need it
+     (mostly everywhere except MIPS, which has signed addresses) as
+     the later would go through gdbarch_pointer_to_address and thus
+     return a CORE_ADDR with high bits set on architectures that
+     encode address spaces and other things in CORE_ADDR.  */
+  bfd_endian byte_order = gdbarch_byte_order (get_frame_arch (frame));
+  LONGEST pointer_offset
+    = extract_signed_integer (value_contents (value).data (),
+			      TYPE_LENGTH (type), byte_order);
+
+  return closure->get_location ().indirect_implicit_ptr (frame, type,
+							 pointer_offset,
+							 bit_offset, bit_length);
+}
+
+/* Implementation of the coerce_ref method of lval_funcs for synthetic C++
+   references.  */
+
+static value *
+coerce_closure_ref (const value *value)
+{
+  struct type *type = check_typedef (value_type (value));
+
+  if (value_bits_synthetic_pointer (value, value_embedded_offset (value),
+				    HOST_CHAR_BIT * TYPE_LENGTH (type)))
+    {
+      computed_closure *closure
+	= (computed_closure *) value_computed_closure (value);
+      frame_info *frame = get_selected_frame (_("No frame selected."));
+
+      return closure->get_location ().indirect_implicit_ptr (frame, type);
+    }
+  else
+    {
+      /* Else: not a synthetic reference; do nothing.  */
+      return nullptr;
+    }
+}
+
 struct piece_closure
 {
   /* Reference count.  */
-- 
2.17.1


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

* [PATCH v4 15/28] Add to_gdb_value method to DWARF entry class
  2021-11-05 11:38 [PATCH v4 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (13 preceding siblings ...)
  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
  2021-11-05 11:38 ` [PATCH v4 16/28] Change DWARF stack to use new dwarf_entry classes Zoran Zaric
                   ` (12 subsequent siblings)
  27 siblings, 0 replies; 38+ messages in thread
From: Zoran Zaric @ 2021-11-05 11:38 UTC (permalink / raw)
  To: gdb-patches

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


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

* [PATCH v4 16/28] Change DWARF stack to use new dwarf_entry classes
  2021-11-05 11:38 [PATCH v4 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (14 preceding siblings ...)
  2021-11-05 11:38 ` [PATCH v4 15/28] Add to_gdb_value method to DWARF entry class Zoran Zaric
@ 2021-11-05 11:38 ` Zoran Zaric
  2021-11-05 11:38 ` [PATCH v4 17/28] Remove old computed struct value callbacks Zoran Zaric
                   ` (11 subsequent siblings)
  27 siblings, 0 replies; 38+ messages in thread
From: Zoran Zaric @ 2021-11-05 11:38 UTC (permalink / raw)
  To: gdb-patches

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

To replace existing DWARF stack element (dwarf_stack_value) with
dwarf_entry class based objects, a support for conversion between
struct value and the new classes is needed. The reason for this is
that dwarf_entry based classes are not designed to be visible outside
the expr.c file. This makes the DWARF expression evaluator more self
contained. This can be beneficial if there is ever a need to have a
DWARF support in gdbserver.

In the previous patch the conversion between the DWARF entry classes to
the struct value has been already added in a form of a to_gdb_value
method.

The interface that is still missing is to convert from struct value to
the DWARF entry classes. New static function gdb_value_to_dwarf_entry
has been added for this purpose.

We also need a way to perform DWARF arithmetic and logical operations
on DWARF values and for this a new set of static functions
(dwarf_value_X) has been provided.

Currently the existing struct value operations are used under the
hood of these functions to avoid the code duplication. Vector types
are planned to be promoted to base types in the future anyway which
means that the operations subset needed is just going to grow.

Also, dwarf_entry class declaration had to be temporarily moved to the
expr.h file so that unique_ptr wrapper type could be used in some
dwarf_expr_context method declaration and will be moved back to the
expr.c file in one of the next patches.

Now, everything is ready so that the DWARF stack element can easily be
swapped out.

It is worth mentioning that a few tests under gdb/testsuite/gdb.dwarf2/
folder, also had to be changed to reflect the design change which
effected an edge case error message text. Tests that had to be changed
slightly are: dw2-param-error.exp, dw2-stack-boundary.exp and
dw2_op_call.exp. The reason for this is that they all contained a
DWARF expression that once evaluated resulted in a stack underflow
error reported by a fetch method, but with the switch to the new stack
element type and a bit different stack algorithm, the message can no
longer be reported by that method, but by a stack pop method instead.

gdb/ChangeLog:

        * dwarf2/expr.c (gdb_value_to_dwarf_entry): New function.
        (to_location): New function.
        (to_value): New function.
        (dwarf_value_cast_op): New function.
        (dwarf_value_complement_op): New function.
        (dwarf_value_negation_op): New function.
        (dwarf_value_binary_op): New function.
        (dwarf_value_less_op): New function.
        (dwarf_value_equal_op): New function.
        (allocate_piece_closure): Remove unused function.
        (dwarf_expr_context::push): Change to use dwarf_entry based
        classes.
        (dwarf_expr_context::push_address): Change to use dwarf_entry
        based classes.
        (dwarf_expr_context::fetch): Change to use dwarf_entry based
        classes.
        (dwarf_expr_context::read_mem): Remove method.
        (dwarf_expr_context::fetch_result): Change to use dwarf_entry
        based classes.
        (dwarf_expr_context::fetch_address): Change to use dwarf_entry
        based classes.
        (dwarf_expr_context::fetch_in_stack_memory): Remove method.
        (dwarf_expr_context::add_piece): Change to use dwarf_entry based
        classes.
        (dwarf_expr_context::execute_stack_op): Change to use dwarf_entry
        based classes.
        (dwarf_location::clone): New method.
        (dwarf_value::clone): New method.
        * dwarf2/expr.h (class dwarf_entry): New declaration.
        (struct dwarf_stack_value): Remove structure.
        (struct dwarf_expr_context): Change to use dwarf_entry based.
        (dwarf_entry::clone): New method.

gdb/testsuite/ChangeLog:

        * gdb.dwarf2/dw2-param-error.exp: Error message text change.
        * gdb.dwarf2/dw2-stack-boundry.exp: Error message text change.
        * gdb.dwarf2/dw2-op-call.exp Error message text change.
---
 gdb/dwarf2/expr.c                             | 1374 ++++++++---------
 gdb/dwarf2/expr.h                             |   92 +-
 gdb/testsuite/gdb.dwarf2/dw2-op-call.exp      |    2 +-
 gdb/testsuite/gdb.dwarf2/dw2-param-error.exp  |    2 +-
 .../gdb.dwarf2/dw2-stack-boundary.exp         |    2 +-
 5 files changed, 711 insertions(+), 761 deletions(-)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index ac26b4c5613..b77fe81eb50 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -36,6 +36,12 @@
 #include "inferior.h"
 #include "observable.h"
 
+/* DWARF evaluator only supports targets with byte size of 8 bits.
+
+   To avoid using hard coded number everywhere, the existing
+   HOST_CHAR_BIT constant is used, because it is guaranteed to
+   always be equal 8.  */
+
 /* Cookie for gdbarch data.  */
 
 static struct gdbarch_data *dwarf_arch_cookie;
@@ -402,21 +408,6 @@ class computed_closure : public refcounted_object
   frame_info *m_frame = nullptr;
 };
 
-/* Base class that describes entries found on a DWARF expression
-   evaluation stack.  */
-
-class dwarf_entry
-{
-protected:
-  /* Not expected to be called on it's own.  */
-  dwarf_entry () = default;
-
-public:
-  virtual ~dwarf_entry () = default;
-};
-
-using dwarf_entry_up = std::unique_ptr<dwarf_entry>;
-
 /* Location description entry found on a DWARF expression evaluation
    stack.
 
@@ -436,6 +427,11 @@ class dwarf_location : public dwarf_entry
 public:
   virtual ~dwarf_location () = default;
 
+  dwarf_entry_up clone () const override final
+  {
+    return this->clone_location ();
+  }
+
   /* Clone the location and return the result as a
      dwarf_location pointer.  */
   virtual std::unique_ptr<dwarf_location> clone_location () const = 0;
@@ -693,6 +689,11 @@ class dwarf_value final : public dwarf_entry
     m_gdb_value = gdb_value;
   }
 
+  dwarf_entry_up clone () const override
+  {
+    return make_unique<dwarf_value> (*this);
+  }
+
   gdb::array_view<const gdb_byte> contents () const
   {
     return m_contents;
@@ -1965,6 +1966,118 @@ dwarf_composite::to_gdb_value (frame_info *frame, struct type *type,
   return retval;
 }
 
+/* Return ENTRY as a dwarf_location.
+   If already a dwarf_location, return it as is, otherwise convert it.  */
+
+static dwarf_location_up
+to_location (dwarf_entry_up entry, gdbarch *arch)
+{
+  dwarf_location *location = dynamic_cast<dwarf_location *> (entry.get ());
+
+  if (location != nullptr)
+    {
+      entry.release ();
+      return dwarf_location_up (location);
+    }
+
+  dwarf_value *value = dynamic_cast<dwarf_value *> (entry.get ());
+  gdb_assert (value != nullptr);
+
+  return value->to_location (arch);
+}
+
+/* Return ENTRY as a dwarf_value.
+   If already a dwarf_value, return it as is, otherwise convert it.  */
+
+static dwarf_value_up
+to_value (dwarf_entry_up entry, type *address_type)
+{
+  dwarf_value *value = dynamic_cast<dwarf_value *> (entry.get ());
+
+  if (value != nullptr)
+    {
+      entry.release ();
+      return dwarf_value_up (value);
+    }
+
+  dwarf_location *location = dynamic_cast<dwarf_location *> (entry.get ());
+  gdb_assert (location != nullptr);
+
+  return location->to_value (address_type);
+}
+
+/* Set of functions that perform different arithmetic operations
+   on dwarf_value arguments.
+
+   Currently the existing struct value operations are used under the
+   hood to avoid the code duplication.  Vector types are planned to be
+   promoted to base types in the future anyway which means that the
+   operations subset needed is just going to grow anyway.  */
+
+/* Compare two DWARF value's ARG1 and ARG2 for equality in a context
+   of a value entry comparison.  */
+
+static bool
+dwarf_value_equal_op (dwarf_value &arg1, dwarf_value &arg2)
+{
+  struct value *arg1_value = arg1.to_gdb_value (arg1.type ());
+  struct value *arg2_value = arg2.to_gdb_value (arg2.type ());
+  return value_equal (arg1_value, arg2_value);
+}
+
+/* Compare if DWARF value ARG1 is less then DWARF value ARG2 in a
+   context of a value entry comparison.   */
+
+static bool
+dwarf_value_less_op (dwarf_value &arg1, dwarf_value &arg2)
+{
+  struct value *arg1_value = arg1.to_gdb_value (arg1.type ());
+  struct value *arg2_value = arg2.to_gdb_value (arg2.type ());
+  return value_less (arg1_value, arg2_value);
+}
+
+/* Apply binary operation OP on given ARG1 and ARG2 arguments
+   and return a new value entry containing the result of that
+   operation.  */
+
+static dwarf_value_up
+dwarf_value_binary_op (dwarf_value &arg1, dwarf_value &arg2,
+		       enum exp_opcode op)
+{
+  struct value *arg1_value = arg1.to_gdb_value (arg1.type ());
+  struct value *arg2_value = arg2.to_gdb_value (arg2.type ());
+  return make_unique<dwarf_value> (value_binop (arg1_value, arg2_value, op));
+}
+
+/* Apply a negation operation on ARG and return a new value entry
+   containing the result of that operation.  */
+
+static dwarf_value_up
+dwarf_value_negation_op (dwarf_value &arg)
+{
+  return make_unique<dwarf_value> (value_neg (arg.to_gdb_value (arg.type ())));
+}
+
+/* Apply a complement operation on ARG and return a new value entry
+   containing the result of that operation.  */
+
+static dwarf_value_up
+dwarf_value_complement_op (dwarf_value &arg)
+{
+  value *result = value_complement (arg.to_gdb_value (arg.type ()));
+  return make_unique<dwarf_value> (result);
+}
+
+/* Apply a cast operation on ARG and return a new value entry
+   containing the result of that operation.  */
+
+static dwarf_value_up
+dwarf_value_cast_op (dwarf_value &arg, struct type *type)
+{
+  struct value *result = value_cast (type, arg.to_gdb_value (arg.type ()));
+  return make_unique<dwarf_value> (result);
+}
+
 static void *
 copy_value_closure (const value *v)
 {
@@ -2199,6 +2312,56 @@ coerce_closure_ref (const value *value)
     }
 }
 
+/* Convert struct value VALUE to the matching DWARF entry
+   representation.  ARCH describes an architecture of the new
+   entry.  */
+
+static dwarf_location_up
+gdb_value_to_dwarf_entry (gdbarch *arch, struct value *value)
+{
+  struct type *type = value_type (value);
+
+  /* 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 (arch);
+  LONGEST offset = value_offset (value) * unit_size;
+
+  switch (value_lval_const (value))
+    {
+      /* We can only convert struct value to a location because
+	 we can't distinguish between the implicit value and
+	 not_lval.  */
+    case not_lval:
+      {
+	gdb_byte *contents_start = value_contents_raw (value).data () + offset;
+
+	return make_unique<dwarf_implicit>
+	  (arch, gdb::array_view<const gdb_byte> (contents_start,
+						  TYPE_LENGTH (type)),
+	   type_byte_order (type));
+      }
+    case lval_memory:
+      return make_unique<dwarf_memory> (arch, value_address (value),
+					value_stack (value));
+    case lval_register:
+      return make_unique<dwarf_register> (arch, VALUE_REGNUM (value), offset);
+    case lval_computed:
+      {
+	/* Dwarf entry is enclosed by the closure anyway so we just
+	   need to unwrap it here.  */
+	computed_closure *closure
+	  = ((computed_closure *) value_computed_closure (value));
+
+	const dwarf_location &location = closure->get_location ();
+	dwarf_location_up location_copy = location.clone_location ();
+	location_copy->add_bit_offset (offset * HOST_CHAR_BIT);
+	return location_copy;
+      }
+    default:
+      internal_error (__FILE__, __LINE__, _("invalid location type"));
+  }
+}
+
 struct piece_closure
 {
   /* Reference count.  */
@@ -2218,34 +2381,6 @@ struct piece_closure
   struct frame_id frame_id;
 };
 
-/* Allocate a closure for a value formed from separately-described
-   PIECES.  */
-
-static piece_closure *
-allocate_piece_closure (dwarf2_per_cu_data *per_cu,
-			dwarf2_per_objfile *per_objfile,
-			std::vector<dwarf_expr_piece> &&pieces,
-			frame_info *frame)
-{
-  piece_closure *c = new piece_closure;
-
-  c->refc = 1;
-  /* We must capture this here due to sharing of DWARF state.  */
-  c->per_objfile = per_objfile;
-  c->per_cu = per_cu;
-  c->pieces = std::move (pieces);
-  if (frame == nullptr)
-    c->frame_id = null_frame_id;
-  else
-    c->frame_id = get_frame_id (frame);
-
-  for (dwarf_expr_piece &piece : c->pieces)
-    if (piece.location == DWARF_VALUE_STACK)
-      value_incref (piece.v.value);
-
-  return c;
-}
-
 /* Read or write a pieced value V.  If FROM != NULL, operate in "write
    mode": copy FROM into the pieces comprising V.  If FROM == NULL,
    operate in "read mode": fetch the contents of the (lazy) value V by
@@ -2827,43 +2962,47 @@ dwarf_expr_context::dwarf_expr_context (dwarf2_per_objfile *per_objfile,
 {
 }
 
-/* Push VALUE onto the stack.  */
+/* Push ENTRY onto the stack.  */
 
 void
-dwarf_expr_context::push (struct value *value, bool in_stack_memory)
+dwarf_expr_context::push (dwarf_entry_up entry)
 {
-  this->m_stack.emplace_back (value, in_stack_memory);
+  this->m_stack.emplace_back (std::move (entry));
 }
 
-/* Push VALUE onto the stack.  */
+/* Push ADDR onto the stack.  */
 
 void
-dwarf_expr_context::push_address (CORE_ADDR value, bool in_stack_memory)
+dwarf_expr_context::push_address (CORE_ADDR addr, bool in_stack_memory)
 {
-  push (value_from_ulongest (address_type (), value), in_stack_memory);
+  this->m_stack.emplace_back (std::make_unique<dwarf_memory>
+    (this->m_per_objfile->objfile->arch (), addr, in_stack_memory));
 }
 
+
 /* Pop the top item off of the stack.  */
 
-void
+dwarf_entry_up
 dwarf_expr_context::pop ()
 {
   if (this->m_stack.empty ())
     error (_("dwarf expression stack underflow"));
 
+  dwarf_entry_up entry = std::move (this->m_stack.back ());
   this->m_stack.pop_back ();
+  return entry;
 }
 
 /* Retrieve the N'th item on the stack.  */
 
-struct value *
+dwarf_entry &
 dwarf_expr_context::fetch (int n)
 {
   if (this->m_stack.size () <= n)
      error (_("Asked for position %d of stack, "
 	      "stack only has %zu elements on it."),
 	    n, this->m_stack.size ());
-  return this->m_stack[this->m_stack.size () - (1 + n)].value;
+  return *this->m_stack[this->m_stack.size () - (1 + n)];
 }
 
 /* See expr.h.  */
@@ -2907,7 +3046,6 @@ dwarf_expr_context::get_base_type (cu_offset die_cu_off)
 
   if (result == nullptr)
     error (_("Could not find type for operation"));
-
   return result;
 }
 
@@ -2938,31 +3076,6 @@ dwarf_expr_context::dwarf_call (cu_offset die_cu_off)
 
 /* See expr.h.  */
 
-void
-dwarf_expr_context::read_mem (gdb_byte *buf, CORE_ADDR addr,
-			      size_t length)
-{
-  if (length == 0)
-    return;
-
-  /* Prefer the passed-in memory, if it exists.  */
-  if (this->m_addr_info != nullptr)
-    {
-      CORE_ADDR offset = addr - this->m_addr_info->addr;
-
-      if (offset < this->m_addr_info->valaddr.size ()
-	  && offset + length <= this->m_addr_info->valaddr.size ())
-	{
-	  memcpy (buf, this->m_addr_info->valaddr.data (), length);
-	  return;
-	}
-    }
-
-  read_memory (addr, buf, length);
-}
-
-/* See expr.h.  */
-
 void
 dwarf_expr_context::push_dwarf_reg_entry_value (call_site_parameter_kind kind,
 						call_site_parameter_u kind_u,
@@ -3015,7 +3128,6 @@ value *
 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)
@@ -3024,148 +3136,17 @@ dwarf_expr_context::fetch_result (struct type *type, struct type *subobj_type,
   if (subobj_type == nullptr)
     subobj_type = type;
 
-  if (this->m_pieces.size () > 0)
+  if (as_lval)
     {
-      ULONGEST bit_size = 0;
-
-      for (dwarf_expr_piece &piece : this->m_pieces)
-	bit_size += piece.size;
-      /* Complain if the expression is larger than the size of the
-	 outer type.  */
-      if (bit_size > 8 * TYPE_LENGTH (type))
-	invalid_synthetic_pointer ();
-
-      piece_closure *c
-	= allocate_piece_closure (this->m_per_cu, this->m_per_objfile,
-				  std::move (this->m_pieces), this->m_frame);
-      retval = allocate_computed_value (subobj_type,
-					&pieced_value_funcs, c);
-      set_value_offset (retval, subobj_offset);
+      dwarf_location_up location = to_location (pop (), arch);
+      return location->to_gdb_value (this->m_frame, type,
+				     subobj_type, subobj_offset);
     }
   else
     {
-      /* If AS_LVAL is false, means that the implicit conversion
-	 from a location description to value is expected.  */
-      if (!as_lval)
-	this->m_location = DWARF_VALUE_STACK;
-
-      switch (this->m_location)
-	{
-	case DWARF_VALUE_REGISTER:
-	  {
-	    gdbarch *f_arch = get_frame_arch (this->m_frame);
-	    int dwarf_regnum
-	      = longest_to_int (value_as_long (this->fetch (0)));
-	    int gdb_regnum = dwarf_reg_to_regnum_or_error (f_arch,
-							   dwarf_regnum);
-
-	    if (subobj_offset != 0)
-	      error (_("cannot use offset on synthetic pointer to register"));
-
-	    gdb_assert (this->m_frame != NULL);
-
-	    retval = value_from_register (subobj_type, gdb_regnum,
-					  this->m_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 *tmp = allocate_value (subobj_type);
-		value_contents_copy (tmp, 0, retval, 0,
-				     TYPE_LENGTH (subobj_type));
-		retval = tmp;
-	      }
-	  }
-	  break;
-
-	case DWARF_VALUE_MEMORY:
-	  {
-	    struct type *ptr_type;
-	    CORE_ADDR address = this->fetch_address (0);
-	    bool in_stack_memory = this->fetch_in_stack_memory (0);
-
-	    /* DW_OP_deref_size (and possibly other operations too) may
-	       create a pointer instead of an address.  Ideally, the
-	       pointer to address conversion would be performed as part
-	       of those operations, but the type of the object to
-	       which the address refers is not known at the time of
-	       the operation.  Therefore, we do the conversion here
-	       since the type is readily available.  */
-
-	    switch (subobj_type->code ())
-	      {
-		case TYPE_CODE_FUNC:
-		case TYPE_CODE_METHOD:
-		  ptr_type = builtin_type (arch)->builtin_func_ptr;
-		  break;
-		default:
-		  ptr_type = builtin_type (arch)->builtin_data_ptr;
-		  break;
-	      }
-	    address = value_as_address (value_from_pointer (ptr_type, address));
-
-	    retval = value_at_lazy (subobj_type,
-				    address + subobj_offset);
-	    if (in_stack_memory)
-	      set_value_stack (retval, 1);
-	  }
-	  break;
-
-	case DWARF_VALUE_STACK:
-	  {
-	    value *val = this->fetch (0);
-	    size_t n = TYPE_LENGTH (value_type (val));
-	    size_t len = TYPE_LENGTH (subobj_type);
-	    size_t max = TYPE_LENGTH (type);
-
-	    if (subobj_offset + len > max)
-	      invalid_synthetic_pointer ();
-
-	    retval = allocate_value (subobj_type);
-
-	    /* The given offset is relative to the actual object.  */
-	    if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG)
-	      subobj_offset += n - max;
-
-	    memcpy (value_contents_raw (retval).data (),
-		    value_contents_all (val).data () + subobj_offset, len);
-	  }
-	  break;
-
-	case DWARF_VALUE_LITERAL:
-	  {
-	    size_t n = TYPE_LENGTH (subobj_type);
-
-	    if (subobj_offset + n > this->m_len)
-	      invalid_synthetic_pointer ();
-
-	    retval = allocate_value (subobj_type);
-	    bfd_byte *contents = value_contents_raw (retval).data ();
-	    memcpy (contents, this->m_data + subobj_offset, n);
-	  }
-	  break;
-
-	case DWARF_VALUE_OPTIMIZED_OUT:
-	  retval = allocate_optimized_out_value (subobj_type);
-	  break;
-
-	  /* DWARF_VALUE_IMPLICIT_POINTER was converted to a pieced
-	     operation by execute_stack_op.  */
-	case DWARF_VALUE_IMPLICIT_POINTER:
-	  /* DWARF_VALUE_OPTIMIZED_OUT can't occur in this context --
-	     it can only be encountered when making a piece.  */
-	default:
-	  internal_error (__FILE__, __LINE__, _("invalid location type"));
-	}
+      dwarf_value_up value = to_value (pop (), address_type ());
+      return value->to_gdb_value (subobj_type, subobj_offset);
     }
-
-  set_value_initialized (retval, this->m_initialized);
-
-  return retval;
 }
 
 /* See expr.h.  */
@@ -3240,103 +3221,68 @@ get_signed_type (struct gdbarch *gdbarch, struct type *type)
     }
 }
 
-/* Retrieve the N'th item on the stack, converted to an address.  */
-
-CORE_ADDR
-dwarf_expr_context::fetch_address (int n)
-{
-  gdbarch *arch = this->m_per_objfile->objfile->arch ();
-  value *result_val = fetch (n);
-  bfd_endian byte_order = gdbarch_byte_order (arch);
-  ULONGEST result;
-
-  dwarf_require_integral (value_type (result_val));
-  result = extract_unsigned_integer (value_contents (result_val).data (),
-				     TYPE_LENGTH (value_type (result_val)),
-				     byte_order);
-
-  /* For most architectures, calling extract_unsigned_integer() alone
-     is sufficient for extracting an address.  However, some
-     architectures (e.g. MIPS) use signed addresses and using
-     extract_unsigned_integer() will not produce a correct
-     result.  Make sure we invoke gdbarch_integer_to_address()
-     for those architectures which require it.  */
-  if (gdbarch_integer_to_address_p (arch))
-    {
-      gdb_byte *buf = (gdb_byte *) alloca (this->m_addr_size);
-      type *int_type = get_unsigned_type (arch,
-					  value_type (result_val));
-
-      store_unsigned_integer (buf, this->m_addr_size, byte_order, result);
-      return gdbarch_integer_to_address (arch, int_type, buf);
-    }
-
-  return (CORE_ADDR) result;
-}
-
-/* Retrieve the in_stack_memory flag of the N'th item on the stack.  */
-
-bool
-dwarf_expr_context::fetch_in_stack_memory (int n)
-{
-  if (this->m_stack.size () <= n)
-     error (_("Asked for position %d of stack, "
-	      "stack only has %zu elements on it."),
-	    n, this->m_stack.size ());
-  return this->m_stack[this->m_stack.size () - (1 + n)].in_stack_memory;
-}
-
 /* Return true if the expression stack is empty.  */
 
 bool
 dwarf_expr_context::stack_empty_p () const
 {
-  return m_stack.empty ();
+  return this->m_stack.empty ();
 }
 
-/* Add a new piece to the dwarf_expr_context's piece list.  */
+/* Add a new piece to the composite on top of the stack.  */
+
 void
-dwarf_expr_context::add_piece (ULONGEST size, ULONGEST offset)
+dwarf_expr_context::add_piece (ULONGEST bit_size, ULONGEST bit_offset)
 {
-  this->m_pieces.emplace_back ();
-  dwarf_expr_piece &p = this->m_pieces.back ();
-
-  p.location = this->m_location;
-  p.size = size;
-  p.offset = offset;
+  dwarf_location_up piece;
+  gdbarch *arch = this->m_per_objfile->objfile->arch ();
 
-  if (p.location == DWARF_VALUE_LITERAL)
-    {
-      p.v.literal.data = this->m_data;
-      p.v.literal.length = this->m_len;
-    }
-  else if (stack_empty_p ())
-    {
-      p.location = DWARF_VALUE_OPTIMIZED_OUT;
-      /* Also reset the context's location, for our callers.  This is
-	 a somewhat strange approach, but this lets us avoid setting
-	 the location to DWARF_VALUE_MEMORY in all the individual
-	 cases in the evaluator.  */
-      this->m_location = DWARF_VALUE_OPTIMIZED_OUT;
-    }
-  else if (p.location == DWARF_VALUE_MEMORY)
+  if (stack_empty_p ())
+    piece = make_unique<dwarf_undefined> (arch);
+  else
     {
-      p.v.mem.addr = fetch_address (0);
-      p.v.mem.in_stack_memory = fetch_in_stack_memory (0);
+      dwarf_entry &top_entry = fetch (0);
+      dwarf_composite *top_entry_as_composite
+	= dynamic_cast <dwarf_composite *> (&top_entry);
+
+      if (top_entry_as_composite == nullptr)
+	piece = to_location (pop (), arch);
+      else
+	piece = make_unique<dwarf_undefined> (arch);
     }
-  else if (p.location == DWARF_VALUE_IMPLICIT_POINTER)
+
+  piece->add_bit_offset (bit_offset);
+
+  /* The composite to push the piece in.  */
+  dwarf_composite *composite;
+
+  /* If stack is empty then it is a start of a new composite.  In the
+     future this will check if the composite is finished or not.  */
+  if (stack_empty_p ())
     {
-      p.v.ptr.die_sect_off = (sect_offset) this->m_len;
-      p.v.ptr.offset = value_as_long (fetch (0));
+      std::unique_ptr<dwarf_composite> new_composite
+	= make_unique<dwarf_composite> (arch, this->m_per_cu);
+      composite = new_composite.get ();
+      push (std::move (new_composite));
     }
-  else if (p.location == DWARF_VALUE_REGISTER)
-    p.v.regno = value_as_long (fetch (0));
   else
     {
-      p.v.value = fetch (0);
+      dwarf_entry &top_entry = fetch (0);
+      composite = dynamic_cast <dwarf_composite *> (&top_entry);
+
+      if (composite == nullptr)
+	{
+	  std::unique_ptr<dwarf_composite> new_composite
+	    = make_unique<dwarf_composite> (arch, this->m_per_cu);
+	  composite = new_composite.get ();
+	  push (std::move (new_composite));
+	}
     }
+
+  composite->add_piece (std::move (piece), bit_size);
 }
 
+
 /* Evaluate the expression at ADDR (LEN bytes long).  */
 
 void
@@ -3383,7 +3329,6 @@ safe_skip_leb128 (const gdb_byte *buf, const gdb_byte *buf_end)
     error (_("DWARF expression error: ran off end of buffer reading leb128 value"));
   return buf;
 }
-\f
 
 /* Check that the current operator is either at the end of an
    expression, or that it is followed by a composition operator or by
@@ -3603,9 +3548,6 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
      CU.  */
   type *address_type = this->address_type ();
 
-  this->m_location = DWARF_VALUE_MEMORY;
-  this->m_initialized = 1;  /* Default is initialized.  */
-
   if (this->m_recursion_depth > this->m_max_recursion_depth)
     error (_("DWARF-2 expression error: Loop detected (%d)."),
 	   this->m_recursion_depth);
@@ -3614,17 +3556,6 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
   while (op_ptr < op_end)
     {
       dwarf_location_atom op = (dwarf_location_atom) *op_ptr++;
-      ULONGEST result;
-      /* Assume the value is not in stack memory.
-	 Code that knows otherwise sets this to true.
-	 Some arithmetic on stack addresses can probably be assumed to still
-	 be a stack address, but we skip this complication for now.
-	 This is just an optimization, so it's always ok to punt
-	 and leave this as false.  */
-      bool in_stack_memory = false;
-      uint64_t uoffset, reg;
-      int64_t offset;
-      value *result_val = NULL;
 
       /* The DWARF expression might have a bug causing an infinite
 	 loop.  In that case, quitting is the only way out.  */
@@ -3664,92 +3595,131 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 	case DW_OP_lit29:
 	case DW_OP_lit30:
 	case DW_OP_lit31:
-	  result = op - DW_OP_lit0;
-	  result_val = value_from_ulongest (address_type, result);
-	  break;
+	  {
+	    ULONGEST result = op - DW_OP_lit0;
+	    push (make_unique<dwarf_value> (result, address_type));
+	    break;
+	  }
 
 	case DW_OP_addr:
-	  result = extract_unsigned_integer (op_ptr,
-					     this->m_addr_size, byte_order);
-	  op_ptr += this->m_addr_size;
-	  /* Some versions of GCC emit DW_OP_addr before
-	     DW_OP_GNU_push_tls_address.  In this case the value is an
-	     index, not an address.  We don't support things like
-	     branching between the address and the TLS op.  */
-	  if (op_ptr >= op_end || *op_ptr != DW_OP_GNU_push_tls_address)
-	    result += this->m_per_objfile->objfile->text_section_offset ();
-	  result_val = value_from_ulongest (address_type, result);
-	  break;
+	  {
+	    ULONGEST result = extract_unsigned_integer (op_ptr,
+							this->m_addr_size,
+							byte_order);
+	    op_ptr += this->m_addr_size;
+	    /* Some versions of GCC emit DW_OP_addr before
+	       DW_OP_GNU_push_tls_address.  In this case the value is an
+	       index, not an address.  We don't support things like
+	       branching between the address and the TLS op.  */
+	    if (op_ptr >= op_end || *op_ptr != DW_OP_GNU_push_tls_address)
+	      {
+		result += this->m_per_objfile->objfile->text_section_offset ();
+		push (make_unique<dwarf_memory> (arch, result));
+	      }
+	    else
+	      /* This is a special case where the value is expected to be
+		 created instead of memory location.  */
+	      push (make_unique<dwarf_value> (result, address_type));
+	    break;
+	  }
 
 	case DW_OP_addrx:
 	case DW_OP_GNU_addr_index:
-	  ensure_have_per_cu (this->m_per_cu, "DW_OP_addrx");
+	  {
+	    ensure_have_per_cu (this->m_per_cu, "DW_OP_addrx");
+	    uint64_t uoffset;
 
-	  op_ptr = safe_read_uleb128 (op_ptr, op_end, &uoffset);
-	  result = dwarf2_read_addr_index (this->m_per_cu, this->m_per_objfile,
-					   uoffset);
-	  result += this->m_per_objfile->objfile->text_section_offset ();
-	  result_val = value_from_ulongest (address_type, result);
-	  break;
+	    op_ptr = safe_read_uleb128 (op_ptr, op_end, &uoffset);
+	    ULONGEST result = dwarf2_read_addr_index (this->m_per_cu,
+						      this->m_per_objfile,
+						      uoffset);
+	    result += this->m_per_objfile->objfile->text_section_offset ();
+	    push (make_unique<dwarf_memory> (arch, result));
+	    break;
+	  }
 	case DW_OP_GNU_const_index:
-	  ensure_have_per_cu (this->m_per_cu, "DW_OP_GNU_const_index");
+	  {
+	    ensure_have_per_cu (this->m_per_cu, "DW_OP_GNU_const_index");
+	    uint64_t uoffset;
 
-	  op_ptr = safe_read_uleb128 (op_ptr, op_end, &uoffset);
-	  result = dwarf2_read_addr_index (this->m_per_cu, this->m_per_objfile,
-					   uoffset);
-	  result_val = value_from_ulongest (address_type, result);
-	  break;
+	    op_ptr = safe_read_uleb128 (op_ptr, op_end, &uoffset);
+	    ULONGEST result = dwarf2_read_addr_index (this->m_per_cu,
+						      this->m_per_objfile,
+						      uoffset);
+	    push (make_unique<dwarf_value> (result, address_type));
+	    break;
+	  }
 
 	case DW_OP_const1u:
-	  result = extract_unsigned_integer (op_ptr, 1, byte_order);
-	  result_val = value_from_ulongest (address_type, result);
-	  op_ptr += 1;
-	  break;
+	  {
+	    ULONGEST result = extract_unsigned_integer (op_ptr, 1, byte_order);
+	    push (make_unique<dwarf_value> (result, address_type));
+	    op_ptr += 1;
+	    break;
+	  }
 	case DW_OP_const1s:
-	  result = extract_signed_integer (op_ptr, 1, byte_order);
-	  result_val = value_from_ulongest (address_type, result);
-	  op_ptr += 1;
-	  break;
+	  {
+	    ULONGEST result = extract_signed_integer (op_ptr, 1, byte_order);
+	    push (make_unique<dwarf_value> (result, address_type));
+	    op_ptr += 1;
+	    break;
+	  }
 	case DW_OP_const2u:
-	  result = extract_unsigned_integer (op_ptr, 2, byte_order);
-	  result_val = value_from_ulongest (address_type, result);
-	  op_ptr += 2;
-	  break;
+	  {
+	    ULONGEST result = extract_unsigned_integer (op_ptr, 2, byte_order);
+	    push (make_unique<dwarf_value> (result, address_type));
+	    op_ptr += 2;
+	    break;
+	  }
 	case DW_OP_const2s:
-	  result = extract_signed_integer (op_ptr, 2, byte_order);
-	  result_val = value_from_ulongest (address_type, result);
-	  op_ptr += 2;
-	  break;
+	  {
+	    ULONGEST result = extract_signed_integer (op_ptr, 2, byte_order);
+	    push (make_unique<dwarf_value> (result, address_type));
+	    op_ptr += 2;
+	    break;
+	  }
 	case DW_OP_const4u:
-	  result = extract_unsigned_integer (op_ptr, 4, byte_order);
-	  result_val = value_from_ulongest (address_type, result);
-	  op_ptr += 4;
-	  break;
+	  {
+	    ULONGEST result = extract_unsigned_integer (op_ptr, 4, byte_order);
+	    push (make_unique<dwarf_value> (result, address_type));
+	    op_ptr += 4;
+	    break;
+	  }
 	case DW_OP_const4s:
-	  result = extract_signed_integer (op_ptr, 4, byte_order);
-	  result_val = value_from_ulongest (address_type, result);
-	  op_ptr += 4;
-	  break;
+	  {
+	    ULONGEST result = extract_signed_integer (op_ptr, 4, byte_order);
+	    push (make_unique<dwarf_value> (result, address_type));
+	    op_ptr += 4;
+	    break;
+	  }
 	case DW_OP_const8u:
-	  result = extract_unsigned_integer (op_ptr, 8, byte_order);
-	  result_val = value_from_ulongest (address_type, result);
-	  op_ptr += 8;
-	  break;
+	  {
+	    ULONGEST result = extract_unsigned_integer (op_ptr, 8, byte_order);
+	    push (make_unique<dwarf_value> (result, address_type));
+	    op_ptr += 8;
+	    break;
+	  }
 	case DW_OP_const8s:
-	  result = extract_signed_integer (op_ptr, 8, byte_order);
-	  result_val = value_from_ulongest (address_type, result);
-	  op_ptr += 8;
-	  break;
+	  {
+	    ULONGEST result = extract_signed_integer (op_ptr, 8, byte_order);
+	    push (make_unique<dwarf_value> (result, address_type));
+	    op_ptr += 8;
+	    break;
+	  }
 	case DW_OP_constu:
-	  op_ptr = safe_read_uleb128 (op_ptr, op_end, &uoffset);
-	  result = uoffset;
-	  result_val = value_from_ulongest (address_type, result);
-	  break;
+	  {
+	    uint64_t uoffset;
+	    op_ptr = safe_read_uleb128 (op_ptr, op_end, &uoffset);
+	    push (make_unique<dwarf_value> ((ULONGEST) uoffset, address_type));
+	    break;
+	  }
 	case DW_OP_consts:
-	  op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
-	  result = offset;
-	  result_val = value_from_ulongest (address_type, result);
-	  break;
+	  {
+	    int64_t offset;
+	    op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
+	    push (make_unique<dwarf_value> ((ULONGEST) offset, address_type));
+	    break;
+	  }
 
 	/* The DW_OP_reg operations are required to occur alone in
 	   location expressions.  */
@@ -3785,21 +3755,23 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 	case DW_OP_reg29:
 	case DW_OP_reg30:
 	case DW_OP_reg31:
-	  dwarf_expr_require_composition (op_ptr, op_end, "DW_OP_reg");
-
-	  result = op - DW_OP_reg0;
-	  result_val = value_from_ulongest (address_type, result);
-	  this->m_location = DWARF_VALUE_REGISTER;
-	  break;
-
 	case DW_OP_regx:
-	  op_ptr = safe_read_uleb128 (op_ptr, op_end, &reg);
-	  dwarf_expr_require_composition (op_ptr, op_end, "DW_OP_regx");
+	  {
+	    ULONGEST result;
 
-	  result = reg;
-	  result_val = value_from_ulongest (address_type, result);
-	  this->m_location = DWARF_VALUE_REGISTER;
-	  break;
+	    if (op == DW_OP_regx)
+	      {
+		uint64_t reg;
+		op_ptr = safe_read_uleb128 (op_ptr, op_end, &reg);
+		result = reg;
+	      }
+	    else
+	      result = op - DW_OP_reg0;
+
+	    dwarf_expr_require_composition (op_ptr, op_end, "DW_OP_reg");
+	    push (make_unique<dwarf_register> (arch, result));
+	    break;
+	  }
 
 	case DW_OP_implicit_value:
 	  {
@@ -3808,19 +3780,28 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 	    op_ptr = safe_read_uleb128 (op_ptr, op_end, &len);
 	    if (op_ptr + len > op_end)
 	      error (_("DW_OP_implicit_value: too few bytes available."));
-	    this->m_len = len;
-	    this->m_data = op_ptr;
-	    this->m_location = DWARF_VALUE_LITERAL;
+	    push (make_unique<dwarf_implicit>
+		    (arch, gdb::array_view<const gdb_byte> (op_ptr, len),
+		     BFD_ENDIAN_UNKNOWN));
 	    op_ptr += len;
 	    dwarf_expr_require_composition (op_ptr, op_end,
 					    "DW_OP_implicit_value");
+	    break;
 	  }
-	  goto no_push;
 
 	case DW_OP_stack_value:
-	  this->m_location = DWARF_VALUE_STACK;
-	  dwarf_expr_require_composition (op_ptr, op_end, "DW_OP_stack_value");
-	  goto no_push;
+	  {
+	    std::unique_ptr<dwarf_value> value
+	      = to_value (pop (), address_type);
+
+	    push (make_unique<dwarf_implicit>
+		    (arch, value->contents (),
+		     type_byte_order (value->type ())));
+
+	    dwarf_expr_require_composition (op_ptr, op_end,
+					    "DW_OP_stack_value");
+	    break;
+	  }
 
 	case DW_OP_implicit_pointer:
 	case DW_OP_GNU_implicit_pointer:
@@ -3831,20 +3812,22 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 	    int ref_addr_size = this->m_per_cu->ref_addr_size ();
 
 	    /* The referred-to DIE of sect_offset kind.  */
-	    this->m_len = extract_unsigned_integer (op_ptr, ref_addr_size,
-						  byte_order);
+	    sect_offset die_offset
+	      = (sect_offset) extract_unsigned_integer (op_ptr, ref_addr_size,
+							byte_order);
 	    op_ptr += ref_addr_size;
 
 	    /* The byte offset into the data.  */
 	    op_ptr = safe_read_sleb128 (op_ptr, op_end, &len);
-	    result = (ULONGEST) len;
-	    result_val = value_from_ulongest (address_type, result);
-
-	    this->m_location = DWARF_VALUE_IMPLICIT_POINTER;
+	    push (make_unique<dwarf_implicit_pointer> (arch,
+						       this->m_per_objfile,
+						       this->m_per_cu,
+						       this->m_addr_size,
+						       die_offset, len));
 	    dwarf_expr_require_composition (op_ptr, op_end,
 					    "DW_OP_implicit_pointer");
+	    break;
 	  }
-	  break;
 
 	case DW_OP_breg0:
 	case DW_OP_breg1:
@@ -3878,78 +3861,90 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 	case DW_OP_breg29:
 	case DW_OP_breg30:
 	case DW_OP_breg31:
+	case DW_OP_bregx:
 	  {
+	    uint64_t reg;
+	    int64_t offset;
+
+	    if (op == DW_OP_bregx)
+	      op_ptr = safe_read_uleb128 (op_ptr, op_end, &reg);
+	    else
+	      reg = op - DW_OP_breg0;
+
 	    op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
 	    ensure_have_frame (this->m_frame, "DW_OP_breg");
 
-	    result = read_addr_from_reg (this->m_frame, op - DW_OP_breg0);
-	    result += offset;
-	    result_val = value_from_ulongest (address_type, result);
+	    gdbarch *frame_arch = get_frame_arch (this->m_frame);
+
+	    int regnum = dwarf_reg_to_regnum_or_error (frame_arch, reg);
+	    ULONGEST reg_size = register_size (frame_arch, regnum);
+	    dwarf_register registr (arch, reg);
+	    dwarf_value_up value = registr.deref (this->m_frame,
+						  this->m_addr_info,
+						  address_type, reg_size);
+	    dwarf_location_up location = value->to_location (arch);
+	    location->add_bit_offset (offset * HOST_CHAR_BIT);
+	    push (std::move (location));
+	    break;
 	  }
-	  break;
-	case DW_OP_bregx:
-	  {
-	    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");
 
-	    result = read_addr_from_reg (this->m_frame, reg);
-	    result += offset;
-	    result_val = value_from_ulongest (address_type, result);
-	  }
-	  break;
 	case DW_OP_fbreg:
 	  {
-	    const gdb_byte *datastart;
-	    size_t datalen;
-
+	    int64_t offset;
 	    op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
-
 	    /* Rather than create a whole new context, we simply
 	       backup the current stack locally and install a new empty stack,
 	       then reset it afterwards, effectively erasing whatever the
 	       recursive call put there.  */
-	    std::vector<dwarf_stack_value> saved_stack = std::move (this->m_stack);
+	    std::vector<std::unique_ptr<dwarf_entry>> saved_stack
+	      = std::move (this->m_stack);
 	    this->m_stack.clear ();
 
-	    /* FIXME: cagney/2003-03-26: This code should be using
-	       get_frame_base_address(), and then implement a dwarf2
-	       specific this_base method.  */
+	    const gdb_byte *datastart;
+	    size_t datalen;
+
 	    this->get_frame_base (&datastart, &datalen);
 	    eval (datastart, datalen);
-	    if (this->m_location == DWARF_VALUE_MEMORY)
-	      result = fetch_address (0);
-	    else if (this->m_location == DWARF_VALUE_REGISTER)
-	      result
-		= read_addr_from_reg (this->m_frame, value_as_long (fetch (0)));
-	    else
-	      error (_("Not implemented: computing frame "
-		       "base using explicit value operator"));
-	    result = result + offset;
-	    result_val = value_from_ulongest (address_type, result);
-	    in_stack_memory = true;
+	    dwarf_entry_up entry = pop ();
+
+	    dwarf_register *registr
+	      = dynamic_cast<dwarf_register *> (entry.get ());
+
+	    if (registr != nullptr)
+	      entry = registr->deref (this->m_frame, this->m_addr_info,
+				      address_type);
+
+	    entry = to_location (std::move (entry), arch);
+	    dwarf_memory *memory = dynamic_cast<dwarf_memory *> (entry.get ());
+
+	    /* If we get anything else then memory location here,
+	       the DWARF standard defines the expression as ill formed.  */
+	    if (memory == nullptr)
+	      ill_formed_expression ();
+
+	    memory->add_bit_offset (offset * HOST_CHAR_BIT);
+	    memory->set_stack (true);
 
 	    /* Restore the content of the original stack.  */
 	    this->m_stack = std::move (saved_stack);
-
-	    this->m_location = DWARF_VALUE_MEMORY;
+	    push (std::move (entry));
+	    break;
 	  }
-	  break;
 
 	case DW_OP_dup:
-	  result_val = fetch (0);
-	  in_stack_memory = fetch_in_stack_memory (0);
+	  push (fetch (0).clone ());
 	  break;
 
 	case DW_OP_drop:
 	  pop ();
-	  goto no_push;
+	  break;
 
 	case DW_OP_pick:
-	  offset = *op_ptr++;
-	  result_val = fetch (offset);
-	  in_stack_memory = fetch_in_stack_memory (offset);
-	  break;
+	  {
+	    int64_t offset = *op_ptr++;
+	    push (fetch (offset).clone ());
+	    break;
+	  }
 	  
 	case DW_OP_swap:
 	  {
@@ -3958,15 +3953,13 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 			"DW_OP_swap.  Need 2, have %zu."),
 		      this->m_stack.size ());
 
-	    dwarf_stack_value &t1 = this->m_stack[this->m_stack.size () - 1];
-	    dwarf_stack_value &t2 = this->m_stack[this->m_stack.size () - 2];
-	    std::swap (t1, t2);
-	    goto no_push;
+	    std::swap (this->m_stack[this->m_stack.size () - 1],
+		       this->m_stack[this->m_stack.size () - 2]);
+	    break;
 	  }
 
 	case DW_OP_over:
-	  result_val = fetch (1);
-	  in_stack_memory = fetch_in_stack_memory (1);
+	  push (fetch (1).clone ());
 	  break;
 
 	case DW_OP_rot:
@@ -3976,13 +3969,11 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 			"DW_OP_rot.  Need 3, have %zu."),
 		      this->m_stack.size ());
 
-	    dwarf_stack_value temp = this->m_stack[this->m_stack.size () - 1];
-	    this->m_stack[this->m_stack.size () - 1]
-	      = this->m_stack[this->m_stack.size () - 2];
-	    this->m_stack[this->m_stack.size () - 2]
-	       = this->m_stack[this->m_stack.size () - 3];
-	    this->m_stack[this->m_stack.size () - 3] = temp;
-	    goto no_push;
+	    std::swap (this->m_stack[this->m_stack.size () - 1],
+		       this->m_stack[this->m_stack.size () - 2]);
+	    std::swap (this->m_stack[this->m_stack.size () - 2],
+		       this->m_stack[this->m_stack.size () - 3]);
+	    break;
 	  }
 
 	case DW_OP_deref:
@@ -3991,72 +3982,63 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 	case DW_OP_GNU_deref_type:
 	  {
 	    int addr_size = (op == DW_OP_deref ? this->m_addr_size : *op_ptr++);
-	    gdb_byte *buf = (gdb_byte *) alloca (addr_size);
-	    CORE_ADDR addr = fetch_address (0);
-	    struct type *type;
-
-	    pop ();
+	    struct type *type = address_type;
 
 	    if (op == DW_OP_deref_type || op == DW_OP_GNU_deref_type)
 	      {
+		uint64_t uoffset;
 		op_ptr = safe_read_uleb128 (op_ptr, op_end, &uoffset);
 		cu_offset type_die_cu_off = (cu_offset) uoffset;
 		type = get_base_type (type_die_cu_off);
+		addr_size = TYPE_LENGTH (type);
 	      }
-	    else
-	      type = address_type;
 
-	    this->read_mem (buf, addr, addr_size);
+	    dwarf_location_up location = to_location (pop (), arch);
+	    push (location->deref (this->m_frame, this->m_addr_info,
+				   type, addr_size));
+	    break;
+	  }
 
-	    /* If the size of the object read from memory is different
-	       from the type length, we need to zero-extend it.  */
-	    if (TYPE_LENGTH (type) != addr_size)
-	      {
-		ULONGEST datum =
-		  extract_unsigned_integer (buf, addr_size, byte_order);
+	case DW_OP_abs:
+	  {
+	    dwarf_value_up arg = to_value (pop (), address_type);
+	    struct value *arg_value = arg->to_gdb_value (arg->type ());
 
-		buf = (gdb_byte *) alloca (TYPE_LENGTH (type));
-		store_unsigned_integer (buf, TYPE_LENGTH (type),
-					byte_order, datum);
-	      }
+	    if (value_less (arg_value, value_zero (arg->type (), not_lval)))
+	      arg = dwarf_value_negation_op (*arg);
 
-	    result_val = value_from_contents_and_address (type, buf, addr);
+	    push (std::move (arg));
 	    break;
 	  }
 
-	case DW_OP_abs:
 	case DW_OP_neg:
+	  {
+	    dwarf_value_up arg = to_value (pop (), address_type);
+	    arg = dwarf_value_negation_op (*arg);
+	    push (std::move (arg));
+	    break;
+	  }
+
 	case DW_OP_not:
+	  {
+	    dwarf_value_up arg = to_value (pop (), address_type);
+	    dwarf_require_integral (arg->type ());
+	    arg = dwarf_value_complement_op (*arg);
+	    push (std::move (arg));
+	    break;
+	  }
+
 	case DW_OP_plus_uconst:
 	  {
-	    /* Unary operations.  */
-	    result_val = fetch (0);
-	    pop ();
+	    dwarf_value_up arg = to_value (pop (), address_type);
+	    dwarf_require_integral (arg->type ());
 
-	    switch (op)
-	      {
-	      case DW_OP_abs:
-		if (value_less (result_val,
-				value_zero (value_type (result_val), not_lval)))
-		  result_val = value_neg (result_val);
-		break;
-	      case DW_OP_neg:
-		result_val = value_neg (result_val);
-		break;
-	      case DW_OP_not:
-		dwarf_require_integral (value_type (result_val));
-		result_val = value_complement (result_val);
-		break;
-	      case DW_OP_plus_uconst:
-		dwarf_require_integral (value_type (result_val));
-		result = value_as_long (result_val);
-		op_ptr = safe_read_uleb128 (op_ptr, op_end, &reg);
-		result += reg;
-		result_val = value_from_ulongest (address_type, result);
-		break;
-	      }
+	    uint64_t reg;
+	    op_ptr = safe_read_uleb128 (op_ptr, op_end, &reg);
+	    ULONGEST result = arg->to_long () + reg;
+	    push (make_unique<dwarf_value> (result, address_type));
+	    break;
 	  }
-	  break;
 
 	case DW_OP_and:
 	case DW_OP_div:
@@ -4077,189 +4059,216 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 	case DW_OP_ne:
 	  {
 	    /* Binary operations.  */
-	    struct value *first, *second;
+	    dwarf_value_up arg2 = to_value (pop (), address_type);
+	    dwarf_value_up arg1 = to_value (pop (), address_type);
 
-	    second = fetch (0);
-	    pop ();
-
-	    first = fetch (0);
-	    pop ();
-
-	    if (! base_types_equal_p (value_type (first), value_type (second)))
+	    if (! base_types_equal_p (arg1->type (), arg2->type ()))
 	      error (_("Incompatible types on DWARF stack"));
 
 	    switch (op)
 	      {
 	      case DW_OP_and:
-		dwarf_require_integral (value_type (first));
-		dwarf_require_integral (value_type (second));
-		result_val = value_binop (first, second, BINOP_BITWISE_AND);
+		dwarf_require_integral (arg1->type ());
+		dwarf_require_integral (arg2->type ());
+		push (dwarf_value_binary_op (*arg1, *arg2, BINOP_BITWISE_AND));
 		break;
 	      case DW_OP_div:
-		result_val = value_binop (first, second, BINOP_DIV);
+		push (dwarf_value_binary_op (*arg1, *arg2, BINOP_DIV));
 		break;
 	      case DW_OP_minus:
-		result_val = value_binop (first, second, BINOP_SUB);
+		push (dwarf_value_binary_op (*arg1, *arg2, BINOP_SUB));
 		break;
 	      case DW_OP_mod:
 		{
 		  int cast_back = 0;
-		  struct type *orig_type = value_type (first);
+		  type *orig_type = arg1->type ();
 
 		  /* We have to special-case "old-style" untyped values
 		     -- these must have mod computed using unsigned
 		     math.  */
 		  if (orig_type == address_type)
 		    {
-		      struct type *utype = get_unsigned_type (arch, orig_type);
+		      type *utype = get_unsigned_type (arch, orig_type);
 
 		      cast_back = 1;
-		      first = value_cast (utype, first);
-		      second = value_cast (utype, second);
+		      arg1 = dwarf_value_cast_op (*arg1, utype);
+		      arg2 = dwarf_value_cast_op (*arg2, utype);
 		    }
 		  /* Note that value_binop doesn't handle float or
 		     decimal float here.  This seems unimportant.  */
-		  result_val = value_binop (first, second, BINOP_MOD);
+		  dwarf_value_up result_val
+		    = dwarf_value_binary_op (*arg1, *arg2, BINOP_MOD);
 		  if (cast_back)
-		    result_val = value_cast (orig_type, result_val);
+		    result_val = dwarf_value_cast_op (*result_val, orig_type);
+
+		  push (std::move (result_val));
 		}
 		break;
 	      case DW_OP_mul:
-		result_val = value_binop (first, second, BINOP_MUL);
+		push (dwarf_value_binary_op (*arg1, *arg2, BINOP_MUL));
 		break;
 	      case DW_OP_or:
-		dwarf_require_integral (value_type (first));
-		dwarf_require_integral (value_type (second));
-		result_val = value_binop (first, second, BINOP_BITWISE_IOR);
+		dwarf_require_integral (arg1->type ());
+		dwarf_require_integral (arg2->type ());
+		push (dwarf_value_binary_op (*arg1, *arg2, BINOP_BITWISE_IOR));
 		break;
 	      case DW_OP_plus:
-		result_val = value_binop (first, second, BINOP_ADD);
+		push (dwarf_value_binary_op (*arg1, *arg2, BINOP_ADD));
 		break;
 	      case DW_OP_shl:
-		dwarf_require_integral (value_type (first));
-		dwarf_require_integral (value_type (second));
-		result_val = value_binop (first, second, BINOP_LSH);
+		dwarf_require_integral (arg1->type ());
+		dwarf_require_integral (arg2->type ());
+		push (dwarf_value_binary_op (*arg1, *arg2, BINOP_LSH));
 		break;
 	      case DW_OP_shr:
-		dwarf_require_integral (value_type (first));
-		dwarf_require_integral (value_type (second));
-		if (!value_type (first)->is_unsigned ())
-		  {
-		    struct type *utype
-		      = get_unsigned_type (arch, value_type (first));
+		{
+		  dwarf_require_integral (arg1->type ());
+		  dwarf_require_integral (arg2->type ());
+		  if (!arg1->type ()->is_unsigned ())
+		    {
+		      struct type *utype
+			= get_unsigned_type (arch, arg1->type ());
 
-		    first = value_cast (utype, first);
-		  }
+		      arg1 = dwarf_value_cast_op (*arg1, utype);
+		    }
 
-		result_val = value_binop (first, second, BINOP_RSH);
-		/* Make sure we wind up with the same type we started
-		   with.  */
-		if (value_type (result_val) != value_type (second))
-		  result_val = value_cast (value_type (second), result_val);
-		break;
+		  dwarf_value_up result_val
+		    = dwarf_value_binary_op (*arg1, *arg2, BINOP_RSH);
+
+		  /* Make sure we wind up with the same type we started
+		     with.  */
+		  if (result_val->type () != arg2->type ())
+		    result_val = dwarf_value_cast_op (*result_val,
+						      arg2->type ());
+
+		  push (std::move (result_val));
+		  break;
+		}
 	      case DW_OP_shra:
-		dwarf_require_integral (value_type (first));
-		dwarf_require_integral (value_type (second));
-		if (value_type (first)->is_unsigned ())
-		  {
-		    struct type *stype
-		      = get_signed_type (arch, value_type (first));
+		{
+		  dwarf_require_integral (arg1->type ());
+		  dwarf_require_integral (arg2->type ());
+		  if (arg1->type ()->is_unsigned ())
+		    {
+		      struct type *stype
+			= get_signed_type (arch, arg1->type ());
 
-		    first = value_cast (stype, first);
-		  }
+		      arg1 = dwarf_value_cast_op (*arg1, stype);
+		    }
 
-		result_val = value_binop (first, second, BINOP_RSH);
-		/* Make sure we wind up with the same type we started
-		   with.  */
-		if (value_type (result_val) != value_type (second))
-		  result_val = value_cast (value_type (second), result_val);
-		break;
+		  dwarf_value_up result_val
+		    = dwarf_value_binary_op (*arg1, *arg2, BINOP_RSH);
+
+		  /* Make sure we wind up with the same type we started  with.  */
+		  if (result_val->type () != arg2->type ())
+		    result_val
+		      = dwarf_value_cast_op (*result_val, arg2->type ());
+
+		  push (std::move (result_val));
+		  break;
+		}
 	      case DW_OP_xor:
-		dwarf_require_integral (value_type (first));
-		dwarf_require_integral (value_type (second));
-		result_val = value_binop (first, second, BINOP_BITWISE_XOR);
+		dwarf_require_integral (arg1->type ());
+		dwarf_require_integral (arg2->type ());
+		push (dwarf_value_binary_op (*arg1, *arg2, BINOP_BITWISE_XOR));
 		break;
 	      case DW_OP_le:
-		/* A <= B is !(B < A).  */
-		result = ! value_less (second, first);
-		result_val = value_from_ulongest (address_type, result);
-		break;
+		{
+		  /* A <= B is !(B < A).  */
+		  ULONGEST result = ! dwarf_value_less_op (*arg2, *arg1);
+		  push (make_unique<dwarf_value> (result, address_type));
+		  break;
+		}
 	      case DW_OP_ge:
-		/* A >= B is !(A < B).  */
-		result = ! value_less (first, second);
-		result_val = value_from_ulongest (address_type, result);
-		break;
+		{
+		  /* A >= B is !(A < B).  */
+		  ULONGEST result = ! dwarf_value_less_op (*arg1, *arg2);
+		  push (make_unique<dwarf_value> (result, address_type));
+		  break;
+		}
 	      case DW_OP_eq:
-		result = value_equal (first, second);
-		result_val = value_from_ulongest (address_type, result);
-		break;
+		{
+		  ULONGEST result = dwarf_value_equal_op (*arg1, *arg2);
+		  push (make_unique<dwarf_value> (result, address_type));
+		  break;
+		}
 	      case DW_OP_lt:
-		result = value_less (first, second);
-		result_val = value_from_ulongest (address_type, result);
-		break;
+		{
+		  ULONGEST result = dwarf_value_less_op (*arg1, *arg2);
+		  push (make_unique<dwarf_value> (result, address_type));
+		  break;
+		}
 	      case DW_OP_gt:
+		{
 		/* A > B is B < A.  */
-		result = value_less (second, first);
-		result_val = value_from_ulongest (address_type, result);
-		break;
+		  ULONGEST result = dwarf_value_less_op (*arg2, *arg1);
+		  push (make_unique<dwarf_value> (result, address_type));
+		  break;
+		}
 	      case DW_OP_ne:
-		result = ! value_equal (first, second);
-		result_val = value_from_ulongest (address_type, result);
-		break;
+		{
+		  ULONGEST result = ! dwarf_value_equal_op (*arg1, *arg2);
+		  push (make_unique<dwarf_value> (result, address_type));
+		  break;
+		}
 	      default:
 		internal_error (__FILE__, __LINE__,
 				_("Can't be reached."));
 	      }
+	    break;
 	  }
-	  break;
 
 	case DW_OP_call_frame_cfa:
-	  ensure_have_frame (this->m_frame, "DW_OP_call_frame_cfa");
+	  {
+	    ensure_have_frame (this->m_frame, "DW_OP_call_frame_cfa");
 
-	  result = dwarf2_frame_cfa (this->m_frame);
-	  result_val = value_from_ulongest (address_type, result);
-	  in_stack_memory = true;
-	  break;
+	    ULONGEST result = dwarf2_frame_cfa (this->m_frame);
+	    push (make_unique<dwarf_memory> (arch, result, true));
+	    break;
+	  }
 
 	case DW_OP_GNU_push_tls_address:
 	case DW_OP_form_tls_address:
-	  /* Variable is at a constant offset in the thread-local
-	  storage block into the objfile for the current thread and
-	  the dynamic linker module containing this expression.  Here
-	  we return returns the offset from that base.  The top of the
-	  stack has the offset from the beginning of the thread
-	  control block at which the variable is located.  Nothing
-	  should follow this operator, so the top of stack would be
-	  returned.  */
-	  result = value_as_long (fetch (0));
-	  pop ();
-	  result = target_translate_tls_address (this->m_per_objfile->objfile,
-						 result);
-	  result_val = value_from_ulongest (address_type, result);
-	  break;
+	  {
+	    /* Variable is at a constant offset in the thread-local
+	       storage block into the objfile for the current thread and
+	       the dynamic linker module containing this expression.  Here
+	       we return returns the offset from that base.  The top of the
+	       stack has the offset from the beginning of the thread
+	       control block at which the variable is located.  Nothing
+	       should follow this operator, so the top of stack would be
+	       returned.  */
+	    dwarf_value_up value = to_value (pop (), address_type);;
+	    ULONGEST result
+	      = target_translate_tls_address (this->m_per_objfile->objfile,
+					      result);
+	    push (make_unique<dwarf_memory> (arch, result));
+	    break;
+	  }
 
 	case DW_OP_skip:
-	  offset = extract_signed_integer (op_ptr, 2, byte_order);
-	  op_ptr += 2;
-	  op_ptr += offset;
-	  goto no_push;
+	  {
+	    int64_t offset = extract_signed_integer (op_ptr, 2, byte_order);
+	    op_ptr += 2;
+	    op_ptr += offset;
+	    break;
+	  }
 
 	case DW_OP_bra:
 	  {
-	    struct value *val;
+	    dwarf_value_up value = to_value (pop (), address_type);
 
-	    offset = extract_signed_integer (op_ptr, 2, byte_order);
+	    int64_t offset = extract_signed_integer (op_ptr, 2, byte_order);
 	    op_ptr += 2;
-	    val = fetch (0);
-	    dwarf_require_integral (value_type (val));
-	    if (value_as_long (val) != 0)
+	    dwarf_require_integral (value->type ());
+
+	    if (value->to_long () != 0)
 	      op_ptr += offset;
-	    pop ();
+	    break;
 	  }
-	  goto no_push;
 
 	case DW_OP_nop:
-	  goto no_push;
+	  break;
 
 	case DW_OP_piece:
 	  {
@@ -4267,16 +4276,9 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 
 	    /* Record the piece.  */
 	    op_ptr = safe_read_uleb128 (op_ptr, op_end, &size);
-	    add_piece (8 * size, 0);
-
-	    /* Pop off the address/regnum, and reset the location
-	       type.  */
-	    if (this->m_location != DWARF_VALUE_LITERAL
-		&& this->m_location != DWARF_VALUE_OPTIMIZED_OUT)
-	      pop ();
-	    this->m_location = DWARF_VALUE_MEMORY;
+	    add_piece (HOST_CHAR_BIT * size, 0);
+	    break;
 	  }
-	  goto no_push;
 
 	case DW_OP_bit_piece:
 	  {
@@ -4286,23 +4288,24 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 	    op_ptr = safe_read_uleb128 (op_ptr, op_end, &size);
 	    op_ptr = safe_read_uleb128 (op_ptr, op_end, &uleb_offset);
 	    add_piece (size, uleb_offset);
-
-	    /* Pop off the address/regnum, and reset the location
-	       type.  */
-	    if (this->m_location != DWARF_VALUE_LITERAL
-		&& this->m_location != DWARF_VALUE_OPTIMIZED_OUT)
-	      pop ();
-	    this->m_location = DWARF_VALUE_MEMORY;
+	    break;
 	  }
-	  goto no_push;
 
 	case DW_OP_GNU_uninit:
-	  if (op_ptr != op_end)
-	    error (_("DWARF-2 expression error: DW_OP_GNU_uninit must always "
-		   "be the very last op."));
+	  {
+	    if (op_ptr != op_end)
+	      error (_("DWARF-2 expression error: DW_OP_GNU_uninit must always "
+		     "be the very last op."));
+
+	    dwarf_entry &entry = fetch (0);
+	    dwarf_location *location = dynamic_cast<dwarf_location *> (&entry);
 
-	  this->m_initialized = 0;
-	  goto no_push;
+	    if (location == nullptr)
+	      ill_formed_expression ();
+
+	    location->set_initialised (false);
+	    break;
+	  }
 
 	case DW_OP_call2:
 	  {
@@ -4310,8 +4313,8 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 	      = (cu_offset) extract_unsigned_integer (op_ptr, 2, byte_order);
 	    op_ptr += 2;
 	    this->dwarf_call (cu_off);
+	    break;
 	  }
-	  goto no_push;
 
 	case DW_OP_call4:
 	  {
@@ -4319,8 +4322,8 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 	      = (cu_offset) extract_unsigned_integer (op_ptr, 4, byte_order);
 	    op_ptr += 4;
 	    this->dwarf_call (cu_off);
+	    break;
 	  }
-	  goto no_push;
 
 	case DW_OP_GNU_variable_value:
 	  {
@@ -4328,15 +4331,23 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 	    int ref_addr_size = this->m_per_cu->ref_addr_size ();
 
 	    sect_offset sect_off
-	      = (sect_offset) extract_unsigned_integer (op_ptr,
-							ref_addr_size,
+	      = (sect_offset) extract_unsigned_integer (op_ptr, ref_addr_size,
 							byte_order);
 	    op_ptr += ref_addr_size;
-	    result_val = sect_variable_value (sect_off, this->m_per_cu,
-					      this->m_per_objfile);
-	    result_val = value_cast (address_type, result_val);
+	    struct value *value = sect_variable_value
+	      (sect_off, this->m_per_cu, this->m_per_objfile);
+	    value = value_cast (address_type, value);
+
+	    dwarf_entry_up entry = gdb_value_to_dwarf_entry (arch, value);
+
+	    if (dynamic_cast<dwarf_undefined *> (entry.get ()) != nullptr)
+	      error_value_optimized_out ();
+
+	    dwarf_location_up location = to_location (std::move (entry), arch);
+	    push (location->deref (this->m_frame, this->m_addr_info,
+				   address_type));
+	    break;
 	  }
-	  break;
 	
 	case DW_OP_entry_value:
 	case DW_OP_GNU_entry_value:
@@ -4356,7 +4367,7 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 		this->push_dwarf_reg_entry_value (CALL_SITE_PARAMETER_DWARF_REG,
 						  kind_u,
 						  -1 /* deref_size */);
-		goto no_push;
+		break;
 	      }
 
 	    kind_u.dwarf_reg = dwarf_block_to_dwarf_reg_deref (op_ptr,
@@ -4369,7 +4380,7 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 		op_ptr += len;
 		this->push_dwarf_reg_entry_value (CALL_SITE_PARAMETER_DWARF_REG,
 						  kind_u, deref_size);
-		goto no_push;
+		break;
 	      }
 
 	    error (_("DWARF-2 expression error: DW_OP_entry_value is "
@@ -4387,111 +4398,94 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 	    this->push_dwarf_reg_entry_value (CALL_SITE_PARAMETER_PARAM_OFFSET,
 					      kind_u,
 					      -1 /* deref_size */);
+	    break;
 	  }
-	  goto no_push;
 
 	case DW_OP_const_type:
 	case DW_OP_GNU_const_type:
 	  {
-	    int n;
-	    const gdb_byte *data;
-	    struct type *type;
-
+	    uint64_t uoffset;
 	    op_ptr = safe_read_uleb128 (op_ptr, op_end, &uoffset);
 	    cu_offset type_die_cu_off = (cu_offset) uoffset;
 
-	    n = *op_ptr++;
-	    data = op_ptr;
+	    int n = *op_ptr++;
+	    const gdb_byte *data = op_ptr;
 	    op_ptr += n;
 
-	    type = get_base_type (type_die_cu_off);
+	    struct type *type = get_base_type (type_die_cu_off);
 
 	    if (TYPE_LENGTH (type) != n)
 	      error (_("DW_OP_const_type has different sizes for type and data"));
 
-	    result_val = value_from_contents (type, data);
+	    push (make_unique<dwarf_value>
+	      (gdb::array_view<const gdb_byte> (data, n), type));
+	    break;
 	  }
-	  break;
 
 	case DW_OP_regval_type:
 	case DW_OP_GNU_regval_type:
 	  {
+	    uint64_t uoffset, reg;
 	    op_ptr = safe_read_uleb128 (op_ptr, op_end, &reg);
 	    op_ptr = safe_read_uleb128 (op_ptr, op_end, &uoffset);
 	    cu_offset type_die_cu_off = (cu_offset) uoffset;
 
 	    ensure_have_frame (this->m_frame, "DW_OP_regval_type");
-
 	    struct type *type = get_base_type (type_die_cu_off);
-	    int regnum
-	      = dwarf_reg_to_regnum_or_error (get_frame_arch (this->m_frame),
-					      reg);
-	    result_val = value_from_register (type, regnum, this->m_frame);
+
+	    dwarf_register registr (arch, reg);
+	    push (registr.deref (this->m_frame, this->m_addr_info, type));
+	    break;
 	  }
-	  break;
 
 	case DW_OP_convert:
 	case DW_OP_GNU_convert:
 	case DW_OP_reinterpret:
 	case DW_OP_GNU_reinterpret:
 	  {
-	    struct type *type;
+	    uint64_t uoffset;
+	    dwarf_value_up value = to_value (pop (), address_type);
 
 	    op_ptr = safe_read_uleb128 (op_ptr, op_end, &uoffset);
 	    cu_offset type_die_cu_off = (cu_offset) uoffset;
 
+	    struct type *type;
+
 	    if (to_underlying (type_die_cu_off) == 0)
 	      type = address_type;
 	    else
 	      type = get_base_type (type_die_cu_off);
 
-	    result_val = fetch (0);
-	    pop ();
-
 	    if (op == DW_OP_convert || op == DW_OP_GNU_convert)
-	      result_val = value_cast (type, result_val);
-	    else if (type == value_type (result_val))
+	      value = dwarf_value_cast_op (*value, type);
+	    else if (type == value->type ())
 	      {
 		/* Nothing.  */
 	      }
-	    else if (TYPE_LENGTH (type)
-		     != TYPE_LENGTH (value_type (result_val)))
+	    else if (TYPE_LENGTH (type) != TYPE_LENGTH (value->type ()))
 	      error (_("DW_OP_reinterpret has wrong size"));
 	    else
-	      result_val
-		= value_from_contents (type,
-				       value_contents_all (result_val).data ());
+	      value = make_unique<dwarf_value> (value->contents (), type);
+	    push (std::move (value));
+	    break;
 	  }
-	  break;
 
 	case DW_OP_push_object_address:
-	  /* Return the address of the object we are currently observing.  */
 	  if (this->m_addr_info == nullptr
 	      || (this->m_addr_info->valaddr.data () == nullptr
 		  && this->m_addr_info->addr == 0))
 	    error (_("Location address is not set."));
 
-	  result_val
-	    = value_from_ulongest (address_type, this->m_addr_info->addr);
+	  /* Return the address of the object we are
+	     currently observing.  */
+	  push (make_unique<dwarf_memory> (arch, this->m_addr_info->addr));
 	  break;
 
 	default:
 	  error (_("Unhandled dwarf expression opcode 0x%x"), op);
 	}
-
-      /* Most things push a result value.  */
-      gdb_assert (result_val != NULL);
-      push (result_val, in_stack_memory);
-    no_push:
-      ;
     }
 
-  /* To simplify our main caller, if the result is an implicit
-     pointer, then make a pieced value.  This is ok because we can't
-     have implicit pointers in contexts where pieces are invalid.  */
-  if (this->m_location == DWARF_VALUE_IMPLICIT_POINTER)
-    add_piece (8 * this->m_addr_size, 0);
-
   this->m_recursion_depth--;
   gdb_assert (this->m_recursion_depth >= 0);
 }
diff --git a/gdb/dwarf2/expr.h b/gdb/dwarf2/expr.h
index 16c5e710ff5..4e74fed4f07 100644
--- a/gdb/dwarf2/expr.h
+++ b/gdb/dwarf2/expr.h
@@ -25,6 +25,23 @@
 #include "leb128.h"
 #include "gdbtypes.h"
 
+/* Base class that describes entries found on a DWARF expression
+   evaluation stack.  */
+
+class dwarf_entry
+{
+protected:
+  /* Not expected to be called on it's own.  */
+  dwarf_entry () = default;
+
+public:
+  virtual ~dwarf_entry () = default;
+
+  virtual std::unique_ptr<dwarf_entry> clone () const = 0;
+};
+
+using dwarf_entry_up = std::unique_ptr<dwarf_entry>;
+
 struct dwarf2_per_objfile;
 
 /* The location of a value.  */
@@ -98,22 +115,6 @@ struct dwarf_expr_piece
   ULONGEST offset;
 };
 
-/* The dwarf expression stack.  */
-
-struct dwarf_stack_value
-{
-  dwarf_stack_value (struct value *value_, int in_stack_memory_)
-  : value (value_), in_stack_memory (in_stack_memory_)
-  {}
-
-  struct value *value;
-
-  /* True if the piece is in memory and is known to be on the program's stack.
-     It is always ok to set this to zero.  This is used, for example, to
-     optimize memory access from the target.  It can vastly speed up backtraces
-     on long latency connections when "set stack-cache on".  */
-  bool in_stack_memory;
-};
 
 /* The expression evaluator works with a dwarf_expr_context, describing
    its current state and its callbacks.  */
@@ -123,7 +124,7 @@ struct dwarf_expr_context
 		      int addr_size);
   virtual ~dwarf_expr_context () = default;
 
-  void push_address (CORE_ADDR value, bool in_stack_memory);
+  void push_address (CORE_ADDR addr, bool in_stack_memory);
 
   /* Evaluate the expression at ADDR (LEN bytes long) in a given PER_CU
      and FRAME context.
@@ -144,8 +145,8 @@ struct dwarf_expr_context
 		   LONGEST subobj_offset = 0);
 
 private:
-  /* The stack of values.  */
-  std::vector<dwarf_stack_value> m_stack;
+  /* The stack of DWARF entries.  */
+  std::vector<dwarf_entry_up> m_stack;
 
   /* Target address size in bytes.  */
   int m_addr_size = 0;
@@ -155,43 +156,6 @@ struct dwarf_expr_context
      depth we'll tolerate before raising an error.  */
   int m_recursion_depth = 0, m_max_recursion_depth = 0x100;
 
-  /* Location of the value.  */
-  dwarf_value_location m_location = DWARF_VALUE_MEMORY;
-
-  /* For DWARF_VALUE_LITERAL, the current literal value's length and
-     data.  For DWARF_VALUE_IMPLICIT_POINTER, LEN is the offset of the
-     target DIE of sect_offset kind.  */
-  ULONGEST m_len = 0;
-  const gdb_byte *m_data = nullptr;
-
-  /* Initialization status of variable: Non-zero if variable has been
-     initialized; zero otherwise.  */
-  int m_initialized = 0;
-
-  /* A vector of pieces.
-
-     Each time DW_OP_piece is executed, we add a new element to the
-     end of this array, recording the current top of the stack, the
-     current location, and the size given as the operand to
-     DW_OP_piece.  We then pop the top value from the stack, reset the
-     location, and resume evaluation.
-
-     The Dwarf spec doesn't say whether DW_OP_piece pops the top value
-     from the stack.  We do, ensuring that clients of this interface
-     expecting to see a value left on the top of the stack (say, code
-     evaluating frame base expressions or CFA's specified with
-     DW_CFA_def_cfa_expression) will get an error if the expression
-     actually marks all the values it computes as pieces.
-
-     If an expression never uses DW_OP_piece, num_pieces will be zero.
-     (It would be nice to present these cases as expressions yielding
-     a single piece, so that callers need not distinguish between the
-     no-DW_OP_piece and one-DW_OP_piece cases.  But expressions with
-     no DW_OP_piece operations have no value to place in a piece's
-     'size' field; the size comes from the surrounding data.  So the
-     two cases need to be handled separately.)  */
-  std::vector<dwarf_expr_piece> m_pieces;
-
   /* We evaluate the expression in the context of this objfile.  */
   dwarf2_per_objfile *m_per_objfile;
 
@@ -206,14 +170,12 @@ struct dwarf_expr_context
 
   void eval (const gdb_byte *addr, size_t len);
   struct type *address_type () const;
-  void push (struct value *value, bool in_stack_memory);
+  void push (dwarf_entry_up value);
   bool stack_empty_p () const;
-  void add_piece (ULONGEST size, ULONGEST offset);
+  void add_piece (ULONGEST bit_size, ULONGEST bit_offset);
   void execute_stack_op (const gdb_byte *op_ptr, const gdb_byte *op_end);
-  void pop ();
-  struct value *fetch (int n);
-  CORE_ADDR fetch_address (int n);
-  bool fetch_in_stack_memory (int n);
+  dwarf_entry_up pop ();
+  dwarf_entry &fetch (int n);
 
   /* Fetch the result of the expression evaluation in a form of
      a struct value, where TYPE, SUBOBJ_TYPE and SUBOBJ_OFFSET
@@ -246,12 +208,6 @@ struct dwarf_expr_context
   void push_dwarf_reg_entry_value (call_site_parameter_kind kind,
 				   call_site_parameter_u kind_u,
 				   int deref_size);
-
-  /* Read LENGTH bytes at ADDR into BUF.  This method also handles the
-     case where a caller of the evaluator passes in some data,
-     but with the address being 0.  In this situation, we arrange for
-     memory reads to come from the passed-in buffer.  */
-  void read_mem (gdb_byte *buf, CORE_ADDR addr, size_t length);
 };
 
 /* Return the value of register number REG (a DWARF register number),
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-op-call.exp b/gdb/testsuite/gdb.dwarf2/dw2-op-call.exp
index 93d8734b017..6035bc3cacc 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-op-call.exp
+++ b/gdb/testsuite/gdb.dwarf2/dw2-op-call.exp
@@ -40,4 +40,4 @@ if ![runto_main] {
     return -1
 }
 gdb_test "p arraynoloc" " = <optimized out>"
-gdb_test "p arraycallnoloc" {Asked for position 0 of stack, stack only has 0 elements on it\.}
+gdb_test "p arraycallnoloc" {dwarf expression stack underflow}
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-param-error.exp b/gdb/testsuite/gdb.dwarf2/dw2-param-error.exp
index 788321c95d5..91c71be9b52 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-param-error.exp
+++ b/gdb/testsuite/gdb.dwarf2/dw2-param-error.exp
@@ -32,4 +32,4 @@ if ![runto f] {
 
 # FAIL was printing:
 # [...] in f (bad=)
-gdb_test "frame" { f \(bad=<error reading variable: Asked for position 0 of stack, stack only has 0 elements on it\.>, good=23\)}
+gdb_test "frame" { f \(bad=<error reading variable: dwarf expression stack underflow>, good=23\)}
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-stack-boundary.exp b/gdb/testsuite/gdb.dwarf2/dw2-stack-boundary.exp
index 054d0c66e71..ab120885ef6 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-stack-boundary.exp
+++ b/gdb/testsuite/gdb.dwarf2/dw2-stack-boundary.exp
@@ -64,5 +64,5 @@ if { $readnow_p } {
 }
 gdb_assert {$w1 && $w2}
 
-gdb_test "p underflow" {Asked for position 0 of stack, stack only has 0 elements on it\.}
+gdb_test "p underflow" {dwarf expression stack underflow}
 gdb_test "p overflow" " = 2"
-- 
2.17.1


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

* [PATCH v4 17/28] Remove old computed struct value callbacks
  2021-11-05 11:38 [PATCH v4 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (15 preceding siblings ...)
  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 ` Zoran Zaric
  2021-11-05 11:38 ` [PATCH v4 18/28] Comments cleanup between expr.h and expr.c Zoran Zaric
                   ` (10 subsequent siblings)
  27 siblings, 0 replies; 38+ messages in thread
From: Zoran Zaric @ 2021-11-05 11:38 UTC (permalink / raw)
  To: gdb-patches

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

After changing the DWARF stack to use the new DWARF entry based
classes, the previous computed struct value callback
infrastructure is not used anymore and can be removed.

gdb/ChangeLog:

        * dwarf2/expr.c (struct piece_closure): Remove structure.
        (rw_pieced_value): Remove unused function.
        (read_pieced_value): Remove unused function.
        (write_pieced_value): Remove unused function.
        (check_pieced_synthetic_pointer): Remove unused function.
        (indirect_pieced_value): Remove unused function.
        (coerce_pieced_ref): Remove unused function.
        (copy_pieced_value_closure): Remove unused function.
        (free_pieced_value_closure): Remove unused function.
        * dwarf2/expr.h (class dwarf_entry): New declaration.
        (struct dwarf_expr_piece): Remove structure.
        (enum dwarf_value_location): Remove enumeration.
---
 gdb/dwarf2/expr.c | 542 ----------------------------------------------
 gdb/dwarf2/expr.h |  72 ------
 2 files changed, 614 deletions(-)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index b77fe81eb50..08f56f070c6 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -2362,548 +2362,6 @@ gdb_value_to_dwarf_entry (gdbarch *arch, struct value *value)
   }
 }
 
-struct piece_closure
-{
-  /* Reference count.  */
-  int refc = 0;
-
-  /* The objfile from which this closure's expression came.  */
-  dwarf2_per_objfile *per_objfile = nullptr;
-
-  /* The CU from which this closure's expression came.  */
-  dwarf2_per_cu_data *per_cu = nullptr;
-
-  /* The pieces describing this variable.  */
-  std::vector<dwarf_expr_piece> pieces;
-
-  /* Frame ID of frame to which a register value is relative, used
-     only by DWARF_VALUE_REGISTER.  */
-  struct frame_id frame_id;
-};
-
-/* Read or write a pieced value V.  If FROM != NULL, operate in "write
-   mode": copy FROM into the pieces comprising V.  If FROM == NULL,
-   operate in "read mode": fetch the contents of the (lazy) value V by
-   composing it from its pieces.  If CHECK_OPTIMIZED is true, then no
-   reading or writing is done; instead the return value of this
-   function is true if any piece is optimized out.  When
-   CHECK_OPTIMIZED is true, FROM must be nullptr.  */
-
-static bool
-rw_pieced_value (value *v, value *from, bool check_optimized)
-{
-  int i;
-  LONGEST offset = 0, max_offset;
-  gdb_byte *v_contents;
-  const gdb_byte *from_contents;
-  piece_closure *c
-    = (piece_closure *) value_computed_closure (v);
-  gdb::byte_vector buffer;
-  bool bits_big_endian = type_byte_order (value_type (v)) == BFD_ENDIAN_BIG;
-
-  gdb_assert (!check_optimized || from == nullptr);
-  if (from != nullptr)
-    {
-      from_contents = value_contents (from).data ();
-      v_contents = nullptr;
-    }
-  else
-    {
-      if (value_type (v) != value_enclosing_type (v))
-	internal_error (__FILE__, __LINE__,
-			_("Should not be able to create a lazy value with "
-			  "an enclosing type"));
-      if (check_optimized)
-	v_contents = nullptr;
-      else
-	v_contents = value_contents_raw (v).data ();
-      from_contents = nullptr;
-    }
-
-  ULONGEST bits_to_skip = 8 * value_offset (v);
-  if (value_bitsize (v))
-    {
-      bits_to_skip += (8 * value_offset (value_parent (v))
-		       + value_bitpos (v));
-      if (from != nullptr
-	  && (type_byte_order (value_type (from))
-	      == BFD_ENDIAN_BIG))
-	{
-	  /* Use the least significant bits of FROM.  */
-	  max_offset = 8 * TYPE_LENGTH (value_type (from));
-	  offset = max_offset - value_bitsize (v);
-	}
-      else
-	max_offset = value_bitsize (v);
-    }
-  else
-    max_offset = 8 * TYPE_LENGTH (value_type (v));
-
-  /* Advance to the first non-skipped piece.  */
-  for (i = 0; i < c->pieces.size () && bits_to_skip >= c->pieces[i].size; i++)
-    bits_to_skip -= c->pieces[i].size;
-
-  for (; i < c->pieces.size () && offset < max_offset; i++)
-    {
-      dwarf_expr_piece *p = &c->pieces[i];
-      size_t this_size_bits, this_size;
-
-      this_size_bits = p->size - bits_to_skip;
-      if (this_size_bits > max_offset - offset)
-	this_size_bits = max_offset - offset;
-
-      switch (p->location)
-	{
-	case DWARF_VALUE_REGISTER:
-	  {
-	    frame_info *frame = frame_find_by_id (c->frame_id);
-	    gdbarch *arch = get_frame_arch (frame);
-	    int gdb_regnum = dwarf_reg_to_regnum_or_error (arch, p->v.regno);
-	    ULONGEST reg_bits = 8 * register_size (arch, gdb_regnum);
-	    int optim, unavail;
-
-	    if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG
-		&& p->offset + p->size < reg_bits)
-	      {
-		/* Big-endian, and we want less than full size.  */
-		bits_to_skip += reg_bits - (p->offset + p->size);
-	      }
-	    else
-	      bits_to_skip += p->offset;
-
-	    this_size = bits_to_bytes (bits_to_skip, this_size_bits);
-	    buffer.resize (this_size);
-
-	    if (from == nullptr)
-	      {
-		/* Read mode.  */
-		read_from_register (frame, gdb_regnum, bits_to_skip / 8,
-				    buffer, &optim, &unavail);
-
-		if (optim)
-		  {
-		    if (check_optimized)
-		      return true;
-		    mark_value_bits_optimized_out (v, offset, this_size_bits);
-		  }
-		if (unavail)
-		  mark_value_bits_unavailable (v, offset, this_size_bits);
-		/* Only copy data if valid.  */
-		if (!optim && !unavail && !check_optimized)
-		  copy_bitwise (v_contents, offset,
-				buffer.data (), bits_to_skip % 8,
-				this_size_bits, bits_big_endian);
-	      }
-	    else
-	      {
-		/* Write mode.  */
-		if (bits_to_skip % 8 != 0 || this_size_bits % 8 != 0)
-		  {
-		    /* Data is copied non-byte-aligned into the register.
-		       Need some bits from original register value.  */
-		    read_from_register (frame, gdb_regnum, bits_to_skip / 8,
-					buffer, &optim, &unavail);
-		    if (optim)
-		      throw_error (OPTIMIZED_OUT_ERROR,
-				   _("Can't do read-modify-write to "
-				     "update bitfield; containing word "
-				     "has been optimized out"));
-		    if (unavail)
-		      throw_error (NOT_AVAILABLE_ERROR,
-				   _("Can't do read-modify-write to "
-				     "update bitfield; containing word "
-				     "is unavailable"));
-		  }
-
-		copy_bitwise (buffer.data (), bits_to_skip % 8,
-			      from_contents, offset,
-			      this_size_bits, bits_big_endian);
-		write_to_register (frame, gdb_regnum, bits_to_skip / 8,
-				   buffer, &optim, &unavail);
-	      }
-	  }
-	  break;
-
-	case DWARF_VALUE_MEMORY:
-	  {
-	    if (check_optimized)
-	      break;
-
-	    bits_to_skip += p->offset;
-
-	    CORE_ADDR start_addr = p->v.mem.addr + bits_to_skip / 8;
-	    bool in_stack_memory = p->v.mem.in_stack_memory;
-	    int unavail = 0;
-
-	    if (bits_to_skip % 8 == 0 && this_size_bits % 8 == 0
-		&& offset % 8 == 0)
-	      {
-		/* Everything is byte-aligned; no buffer needed.  */
-		if (from != NULL)
-		  write_to_memory (start_addr, (from_contents + offset / 8),
-				   this_size_bits / 8, in_stack_memory,
-				   &unavail);
-		else
-		  read_from_memory (start_addr, (v_contents + offset / 8),
-				    this_size_bits / 8, in_stack_memory,
-				    &unavail);
-	      }
-	    else
-	      {
-		this_size = bits_to_bytes (bits_to_skip, this_size_bits);
-		buffer.resize (this_size);
-
-		if (from == NULL)
-		  {
-		    /* Read mode.  */
-		    read_from_memory (start_addr, buffer.data (),
-				      this_size, in_stack_memory,
-				      &unavail);
-		    if (!unavail)
-		      copy_bitwise (v_contents, offset,
-				    buffer.data (), bits_to_skip % 8,
-				    this_size_bits, bits_big_endian);
-		  }
-		else
-		  {
-		    /* Write mode.  */
-		    if (bits_to_skip % 8 != 0 || this_size_bits % 8 != 0)
-		      {
-			if (this_size <= 8)
-			  {
-			    /* Perform a single read for small sizes.  */
-			    read_from_memory (start_addr, buffer.data (),
-					      this_size, in_stack_memory,
-					      &unavail);
-			  }
-			else
-			  {
-			    /* Only the first and last bytes can possibly have
-			       any bits reused.  */
-			    read_from_memory (start_addr, buffer.data (),
-					      1, in_stack_memory,
-					      &unavail);
-			    if (!unavail)
-			      read_from_memory (start_addr + this_size - 1,
-						&buffer[this_size - 1], 1,
-						in_stack_memory, &unavail);
-			  }
-		      }
-
-		    if (!unavail)
-		      {
-			copy_bitwise (buffer.data (), bits_to_skip % 8,
-				      from_contents, offset,
-				      this_size_bits, bits_big_endian);
-			write_to_memory (start_addr, buffer.data (),
-					 this_size, in_stack_memory,
-					 &unavail);
-		      }
-		  }
-	      }
-
-	    if (unavail)
-	      {
-		if (from == NULL)
-		  mark_value_bits_unavailable (v, (offset + bits_to_skip % 8),
-					       this_size_bits);
-		else
-		  throw_error (NOT_AVAILABLE_ERROR,
-			       _("Can't do read-modify-write to "
-				 "update bitfield; containing word "
-				 "is unavailable"));
-	      }
-	  }
-	  break;
-
-	case DWARF_VALUE_STACK:
-	  {
-	    if (check_optimized)
-	      break;
-
-	    if (from != nullptr)
-	      {
-		mark_value_bits_optimized_out (v, offset, this_size_bits);
-		break;
-	      }
-
-	    gdbarch *objfile_gdbarch = c->per_objfile->objfile->arch ();
-	    ULONGEST stack_value_size_bits
-	      = 8 * TYPE_LENGTH (value_type (p->v.value));
-
-	    /* Use zeroes if piece reaches beyond stack value.  */
-	    if (p->offset + p->size > stack_value_size_bits)
-	      break;
-
-	    /* Piece is anchored at least significant bit end.  */
-	    if (gdbarch_byte_order (objfile_gdbarch) == BFD_ENDIAN_BIG)
-	      bits_to_skip += stack_value_size_bits - p->offset - p->size;
-	    else
-	      bits_to_skip += p->offset;
-
-	    copy_bitwise (v_contents, offset,
-			  value_contents_all (p->v.value).data (),
-			  bits_to_skip,
-			  this_size_bits, bits_big_endian);
-	  }
-	  break;
-
-	case DWARF_VALUE_LITERAL:
-	  {
-	    if (check_optimized)
-	      break;
-
-	    if (from != nullptr)
-	      {
-		mark_value_bits_optimized_out (v, offset, this_size_bits);
-		break;
-	      }
-
-	    ULONGEST literal_size_bits = 8 * p->v.literal.length;
-	    size_t n = this_size_bits;
-
-	    /* Cut off at the end of the implicit value.  */
-	    bits_to_skip += p->offset;
-	    if (bits_to_skip >= literal_size_bits)
-	      break;
-	    if (n > literal_size_bits - bits_to_skip)
-	      n = literal_size_bits - bits_to_skip;
-
-	    copy_bitwise (v_contents, offset,
-			  p->v.literal.data, bits_to_skip,
-			  n, bits_big_endian);
-	  }
-	  break;
-
-	case DWARF_VALUE_IMPLICIT_POINTER:
-	    if (from != nullptr)
-	      {
-		mark_value_bits_optimized_out (v, offset, this_size_bits);
-		break;
-	      }
-
-	  /* These bits show up as zeros -- but do not cause the value to
-	     be considered optimized-out.  */
-	  break;
-
-	case DWARF_VALUE_OPTIMIZED_OUT:
-	  if (check_optimized)
-	    return true;
-	  mark_value_bits_optimized_out (v, offset, this_size_bits);
-	  break;
-
-	default:
-	  internal_error (__FILE__, __LINE__, _("invalid location type"));
-	}
-
-      offset += this_size_bits;
-      bits_to_skip = 0;
-    }
-
-  return false;
-}
-
-static void
-read_pieced_value (value *v)
-{
-  rw_pieced_value (v, nullptr, false);
-}
-
-static void
-write_pieced_value (value *to, value *from)
-{
-  rw_pieced_value (to, from, false);
-}
-
-static bool
-is_optimized_out_pieced_value (value *v)
-{
-  return rw_pieced_value (v, nullptr, true);
-}
-
-/* An implementation of an lval_funcs method to see whether a value is
-   a synthetic pointer.  */
-
-static int
-check_pieced_synthetic_pointer (const value *value, LONGEST bit_offset,
-				int bit_length)
-{
-  piece_closure *c = (piece_closure *) value_computed_closure (value);
-  int i;
-
-  bit_offset += 8 * value_offset (value);
-  if (value_bitsize (value))
-    bit_offset += value_bitpos (value);
-
-  for (i = 0; i < c->pieces.size () && bit_length > 0; i++)
-    {
-      dwarf_expr_piece *p = &c->pieces[i];
-      size_t this_size_bits = p->size;
-
-      if (bit_offset > 0)
-	{
-	  if (bit_offset >= this_size_bits)
-	    {
-	      bit_offset -= this_size_bits;
-	      continue;
-	    }
-
-	  bit_length -= this_size_bits - bit_offset;
-	  bit_offset = 0;
-	}
-      else
-	bit_length -= this_size_bits;
-
-      if (p->location != DWARF_VALUE_IMPLICIT_POINTER)
-	return 0;
-    }
-
-  return 1;
-}
-
-/* An implementation of an lval_funcs method to indirect through a
-   pointer.  This handles the synthetic pointer case when needed.  */
-
-static value *
-indirect_pieced_value (value *value)
-{
-  piece_closure *c
-    = (piece_closure *) value_computed_closure (value);
-  int i;
-  dwarf_expr_piece *piece = NULL;
-
-  struct type *type = check_typedef (value_type (value));
-  if (type->code () != TYPE_CODE_PTR)
-    return NULL;
-
-  int bit_length = 8 * TYPE_LENGTH (type);
-  LONGEST bit_offset = 8 * value_offset (value);
-  if (value_bitsize (value))
-    bit_offset += value_bitpos (value);
-
-  for (i = 0; i < c->pieces.size () && bit_length > 0; i++)
-    {
-      dwarf_expr_piece *p = &c->pieces[i];
-      size_t this_size_bits = p->size;
-
-      if (bit_offset > 0)
-	{
-	  if (bit_offset >= this_size_bits)
-	    {
-	      bit_offset -= this_size_bits;
-	      continue;
-	    }
-
-	  bit_length -= this_size_bits - bit_offset;
-	  bit_offset = 0;
-	}
-      else
-	bit_length -= this_size_bits;
-
-      if (p->location != DWARF_VALUE_IMPLICIT_POINTER)
-	return NULL;
-
-      if (bit_length != 0)
-	error (_("Invalid use of DW_OP_implicit_pointer"));
-
-      piece = p;
-      break;
-    }
-
-  gdb_assert (piece != NULL && c->per_cu != nullptr);
-  frame_info *frame = get_selected_frame (_("No frame selected."));
-
-  /* This is an offset requested by GDB, such as value subscripts.
-     However, due to how synthetic pointers are implemented, this is
-     always presented to us as a pointer type.  This means we have to
-     sign-extend it manually as appropriate.  Use raw
-     extract_signed_integer directly rather than value_as_address and
-     sign extend afterwards on architectures that would need it
-     (mostly everywhere except MIPS, which has signed addresses) as
-     the later would go through gdbarch_pointer_to_address and thus
-     return a CORE_ADDR with high bits set on architectures that
-     encode address spaces and other things in CORE_ADDR.  */
-  bfd_endian byte_order = gdbarch_byte_order (get_frame_arch (frame));
-  LONGEST byte_offset
-    = extract_signed_integer (value_contents (value).data (),
-			      TYPE_LENGTH (type), byte_order);
-  byte_offset += piece->v.ptr.offset;
-
-  return indirect_synthetic_pointer (piece->v.ptr.die_sect_off,
-				     byte_offset, c->per_cu,
-				     c->per_objfile, frame, type);
-}
-
-/* Implementation of the coerce_ref method of lval_funcs for synthetic C++
-   references.  */
-
-static value *
-coerce_pieced_ref (const value *value)
-{
-  struct type *type = check_typedef (value_type (value));
-
-  if (value_bits_synthetic_pointer (value, value_embedded_offset (value),
-				    TARGET_CHAR_BIT * TYPE_LENGTH (type)))
-    {
-      const piece_closure *closure
-	= (piece_closure *) value_computed_closure (value);
-      frame_info *frame
-	= get_selected_frame (_("No frame selected."));
-
-      /* gdb represents synthetic pointers as pieced values with a single
-	 piece.  */
-      gdb_assert (closure != NULL);
-      gdb_assert (closure->pieces.size () == 1);
-
-      return indirect_synthetic_pointer
-	(closure->pieces[0].v.ptr.die_sect_off,
-	 closure->pieces[0].v.ptr.offset,
-	 closure->per_cu, closure->per_objfile, frame, type);
-    }
-  else
-    {
-      /* Else: not a synthetic reference; do nothing.  */
-      return NULL;
-    }
-}
-
-static void *
-copy_pieced_value_closure (const value *v)
-{
-  piece_closure *c = (piece_closure *) value_computed_closure (v);
-
-  ++c->refc;
-  return c;
-}
-
-static void
-free_pieced_value_closure (value *v)
-{
-  piece_closure *c = (piece_closure *) value_computed_closure (v);
-
-  --c->refc;
-  if (c->refc == 0)
-    {
-      for (dwarf_expr_piece &p : c->pieces)
-	if (p.location == DWARF_VALUE_STACK)
-	  value_decref (p.v.value);
-
-      delete c;
-    }
-}
-
-/* Functions for accessing a variable described by DW_OP_piece.  */
-static const struct lval_funcs pieced_value_funcs = {
-  read_pieced_value,
-  write_pieced_value,
-  is_optimized_out_pieced_value,
-  indirect_pieced_value,
-  coerce_pieced_ref,
-  check_pieced_synthetic_pointer,
-  copy_pieced_value_closure,
-  free_pieced_value_closure
-};
-
 /* Given context CTX, section offset SECT_OFF, and compilation unit
    data PER_CU, execute the "variable value" operation on the DIE
    found at SECT_OFF.  */
diff --git a/gdb/dwarf2/expr.h b/gdb/dwarf2/expr.h
index 4e74fed4f07..d39a9d9e50c 100644
--- a/gdb/dwarf2/expr.h
+++ b/gdb/dwarf2/expr.h
@@ -44,78 +44,6 @@ using dwarf_entry_up = std::unique_ptr<dwarf_entry>;
 
 struct dwarf2_per_objfile;
 
-/* The location of a value.  */
-enum dwarf_value_location
-{
-  /* The piece is in memory.
-     The value on the dwarf stack is its address.  */
-  DWARF_VALUE_MEMORY,
-
-  /* The piece is in a register.
-     The value on the dwarf stack is the register number.  */
-  DWARF_VALUE_REGISTER,
-
-  /* The piece is on the dwarf stack.  */
-  DWARF_VALUE_STACK,
-
-  /* The piece is a literal.  */
-  DWARF_VALUE_LITERAL,
-
-  /* The piece was optimized out.  */
-  DWARF_VALUE_OPTIMIZED_OUT,
-
-  /* The piece is an implicit pointer.  */
-  DWARF_VALUE_IMPLICIT_POINTER
-};
-
-/* A piece of an object, as recorded by DW_OP_piece or DW_OP_bit_piece.  */
-struct dwarf_expr_piece
-{
-  enum dwarf_value_location location;
-
-  union
-  {
-    struct
-    {
-      /* This piece's address, for DWARF_VALUE_MEMORY pieces.  */
-      CORE_ADDR addr;
-      /* Non-zero if the piece is known to be in memory and on
-	 the program's stack.  */
-      bool in_stack_memory;
-    } mem;
-
-    /* The piece's register number, for DWARF_VALUE_REGISTER pieces.  */
-    int regno;
-
-    /* The piece's literal value, for DWARF_VALUE_STACK pieces.  */
-    struct value *value;
-
-    struct
-    {
-      /* A pointer to the data making up this piece,
-	 for DWARF_VALUE_LITERAL pieces.  */
-      const gdb_byte *data;
-      /* The length of the available data.  */
-      ULONGEST length;
-    } literal;
-
-    /* Used for DWARF_VALUE_IMPLICIT_POINTER.  */
-    struct
-    {
-      /* The referent DIE from DW_OP_implicit_pointer.  */
-      sect_offset die_sect_off;
-      /* The byte offset into the resulting data.  */
-      LONGEST offset;
-    } ptr;
-  } v;
-
-  /* The length of the piece, in bits.  */
-  ULONGEST size;
-  /* The piece offset, in bits.  */
-  ULONGEST offset;
-};
-
-
 /* The expression evaluator works with a dwarf_expr_context, describing
    its current state and its callbacks.  */
 struct dwarf_expr_context
-- 
2.17.1


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

* [PATCH v4 18/28] Comments cleanup between expr.h and expr.c
  2021-11-05 11:38 [PATCH v4 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (16 preceding siblings ...)
  2021-11-05 11:38 ` [PATCH v4 17/28] Remove old computed struct value callbacks Zoran Zaric
@ 2021-11-05 11:38 ` Zoran Zaric
  2021-11-05 11:38 ` [PATCH v4 19/28] Remove dwarf_expr_context from expr.h interface Zoran Zaric
                   ` (9 subsequent siblings)
  27 siblings, 0 replies; 38+ messages in thread
From: Zoran Zaric @ 2021-11-05 11:38 UTC (permalink / raw)
  To: gdb-patches

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

This is just a cosmetic cleanup of the expr.h and expr.c documentation.

gdb/ChangeLog:

        * dwarf2/expr.c: Comments cleanup.
        * dwarf2/expr.h: Comments cleanup.
---
 gdb/dwarf2/expr.c | 42 +++++++++++++++---------------------
 gdb/dwarf2/expr.h | 55 ++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 69 insertions(+), 28 deletions(-)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index 08f56f070c6..ec7a8d13dc8 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -2420,7 +2420,7 @@ dwarf_expr_context::dwarf_expr_context (dwarf2_per_objfile *per_objfile,
 {
 }
 
-/* Push ENTRY onto the stack.  */
+/* See expr.h.  */
 
 void
 dwarf_expr_context::push (dwarf_entry_up entry)
@@ -2428,7 +2428,7 @@ dwarf_expr_context::push (dwarf_entry_up entry)
   this->m_stack.emplace_back (std::move (entry));
 }
 
-/* Push ADDR onto the stack.  */
+/* See expr.h.  */
 
 void
 dwarf_expr_context::push_address (CORE_ADDR addr, bool in_stack_memory)
@@ -2438,7 +2438,7 @@ dwarf_expr_context::push_address (CORE_ADDR addr, bool in_stack_memory)
 }
 
 
-/* Pop the top item off of the stack.  */
+/* See expr.h.  */
 
 dwarf_entry_up
 dwarf_expr_context::pop ()
@@ -2451,7 +2451,7 @@ dwarf_expr_context::pop ()
   return entry;
 }
 
-/* Retrieve the N'th item on the stack.  */
+/* See expr.h.  */
 
 dwarf_entry &
 dwarf_expr_context::fetch (int n)
@@ -2679,7 +2679,7 @@ get_signed_type (struct gdbarch *gdbarch, struct type *type)
     }
 }
 
-/* Return true if the expression stack is empty.  */
+/* See expr.h.  */
 
 bool
 dwarf_expr_context::stack_empty_p () const
@@ -2687,7 +2687,7 @@ dwarf_expr_context::stack_empty_p () const
   return this->m_stack.empty ();
 }
 
-/* Add a new piece to the composite on top of the stack.  */
+/* See expr.h.  */
 
 void
 dwarf_expr_context::add_piece (ULONGEST bit_size, ULONGEST bit_offset)
@@ -2741,7 +2741,7 @@ dwarf_expr_context::add_piece (ULONGEST bit_size, ULONGEST bit_offset)
 }
 
 
-/* Evaluate the expression at ADDR (LEN bytes long).  */
+/* See expr.h.  */
 
 void
 dwarf_expr_context::eval (const gdb_byte *addr, size_t len)
@@ -2755,7 +2755,7 @@ dwarf_expr_context::eval (const gdb_byte *addr, size_t len)
   gdb_assert (this->m_recursion_depth == old_recursion_depth);
 }
 
-/* Helper to read a uleb128 value or throw an error.  */
+/* See expr.h.  */
 
 const gdb_byte *
 safe_read_uleb128 (const gdb_byte *buf, const gdb_byte *buf_end,
@@ -2767,7 +2767,7 @@ safe_read_uleb128 (const gdb_byte *buf, const gdb_byte *buf_end,
   return buf;
 }
 
-/* Helper to read a sleb128 value or throw an error.  */
+/* See expr.h.  */
 
 const gdb_byte *
 safe_read_sleb128 (const gdb_byte *buf, const gdb_byte *buf_end,
@@ -2779,6 +2779,8 @@ safe_read_sleb128 (const gdb_byte *buf, const gdb_byte *buf_end,
   return buf;
 }
 
+/* See expr.h.  */
+
 const gdb_byte *
 safe_skip_leb128 (const gdb_byte *buf, const gdb_byte *buf_end)
 {
@@ -2788,9 +2790,7 @@ safe_skip_leb128 (const gdb_byte *buf, const gdb_byte *buf_end)
   return buf;
 }
 
-/* Check that the current operator is either at the end of an
-   expression, or that it is followed by a composition operator or by
-   DW_OP_GNU_uninit (which should terminate the expression).  */
+/* See expr.h.  */
 
 void
 dwarf_expr_require_composition (const gdb_byte *op_ptr, const gdb_byte *op_end,
@@ -2818,8 +2818,7 @@ base_types_equal_p (struct type *t1, struct type *t2)
   return TYPE_LENGTH (t1) == TYPE_LENGTH (t2);
 }
 
-/* If <BUF..BUF_END] contains DW_FORM_block* with single DW_OP_reg* return the
-   DWARF register number.  Otherwise return -1.  */
+/* See expr.h.  */
 
 int
 dwarf_block_to_dwarf_reg (const gdb_byte *buf, const gdb_byte *buf_end)
@@ -2859,10 +2858,7 @@ dwarf_block_to_dwarf_reg (const gdb_byte *buf, const gdb_byte *buf_end)
   return dwarf_reg;
 }
 
-/* If <BUF..BUF_END] contains DW_FORM_block* with just DW_OP_breg*(0) and
-   DW_OP_deref* return the DWARF register number.  Otherwise return -1.
-   DEREF_SIZE_RETURN contains -1 for DW_OP_deref; otherwise it contains the
-   size from DW_OP_deref_size.  */
+/* See expr.h.  */
 
 int
 dwarf_block_to_dwarf_reg_deref (const gdb_byte *buf, const gdb_byte *buf_end,
@@ -2920,8 +2916,7 @@ dwarf_block_to_dwarf_reg_deref (const gdb_byte *buf, const gdb_byte *buf_end,
   return dwarf_reg;
 }
 
-/* If <BUF..BUF_END] contains DW_FORM_block* with single DW_OP_fbreg(X) fill
-   in FB_OFFSET_RETURN with the X offset and return 1.  Otherwise return 0.  */
+/* See expr.h.  */
 
 int
 dwarf_block_to_fb_offset (const gdb_byte *buf, const gdb_byte *buf_end,
@@ -2946,9 +2941,7 @@ dwarf_block_to_fb_offset (const gdb_byte *buf, const gdb_byte *buf_end,
   return 1;
 }
 
-/* If <BUF..BUF_END] contains DW_FORM_block* with single DW_OP_bregSP(X) fill
-   in SP_OFFSET_RETURN with the X offset and return 1.  Otherwise return 0.
-   The matched SP register number depends on GDBARCH.  */
+/* See expr.h.  */
 
 int
 dwarf_block_to_sp_offset (struct gdbarch *gdbarch, const gdb_byte *buf,
@@ -2988,8 +2981,7 @@ dwarf_block_to_sp_offset (struct gdbarch *gdbarch, const gdb_byte *buf,
   return 1;
 }
 
-/* The engine for the expression evaluator.  Using the context in this
-   object, evaluate the expression between OP_PTR and OP_END.  */
+/* See expr.h.  */
 
 void
 dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
diff --git a/gdb/dwarf2/expr.h b/gdb/dwarf2/expr.h
index d39a9d9e50c..aa371e4bda6 100644
--- a/gdb/dwarf2/expr.h
+++ b/gdb/dwarf2/expr.h
@@ -48,10 +48,17 @@ struct dwarf2_per_objfile;
    its current state and its callbacks.  */
 struct dwarf_expr_context
 {
-  dwarf_expr_context (dwarf2_per_objfile *per_objfile,
-		      int addr_size);
+  /* Create a new context for the expression evaluator.
+
+     We should ever only pass in the PER_OBJFILE and the ADDR_SIZE
+     information should be retrievable from there.  The PER_OBJFILE
+     contains a pointer to the PER_BFD information anyway and the
+     address size information must be the same for the whole BFD.  */
+  dwarf_expr_context (dwarf2_per_objfile *per_objfile, int addr_size);
+
   virtual ~dwarf_expr_context () = default;
 
+  /* Push ADDR onto the stack.  */
   void push_address (CORE_ADDR addr, bool in_stack_memory);
 
   /* Evaluate the expression at ADDR (LEN bytes long) in a given PER_CU
@@ -96,13 +103,38 @@ struct dwarf_expr_context
   /* Property address info used for the evaluation.  */
   const struct property_addr_info *m_addr_info = nullptr;
 
+  /* Evaluate the expression at ADDR (LEN bytes long).  */
   void eval (const gdb_byte *addr, size_t len);
+
+  /* Return the type used for DWARF operations where the type is
+     unspecified in the DWARF spec.  Only certain sizes are
+     supported.  */
   struct type *address_type () const;
-  void push (dwarf_entry_up value);
+
+  /* Push ENTRY onto the stack.  */
+  void push (dwarf_entry_up entry);
+
+  /* Return true if the expression stack is empty.  */
   bool stack_empty_p () const;
+
+  /* Pop a top element of the stack and add as a composite piece
+     with an BIT_OFFSET offset and of a BIT_SIZE size.
+
+     If the following top element of the stack is a composite
+     location description, the piece will be added to it.  Otherwise
+     a new composite location description will be created, pushed on
+     the stack and the piece will be added to that composite.  */
   void add_piece (ULONGEST bit_size, ULONGEST bit_offset);
+
+  /* The engine for the expression evaluator.  Using the context in
+      this object, evaluate the expression between OP_PTR and
+      OP_END.  */
   void execute_stack_op (const gdb_byte *op_ptr, const gdb_byte *op_end);
+
+  /* Pop the top item off of the stack.  */
   dwarf_entry_up pop ();
+
+  /* Retrieve the N'th item on the stack.  */
   dwarf_entry &fetch (int n);
 
   /* Fetch the result of the expression evaluation in a form of
@@ -142,18 +174,32 @@ struct dwarf_expr_context
    read as an address in a given FRAME.  */
 CORE_ADDR read_addr_from_reg (frame_info *frame, int reg);
 
+/* Check that the current operator is either at the end of an
+   expression, or that it is followed by a composition operator or by
+   DW_OP_GNU_uninit (which should terminate the expression).  */
 void dwarf_expr_require_composition (const gdb_byte *, const gdb_byte *,
 				     const char *);
 
+/* If <BUF..BUF_END] contains DW_FORM_block* with single DW_OP_reg* return the
+   DWARF register number.  Otherwise return -1.  */
 int dwarf_block_to_dwarf_reg (const gdb_byte *buf, const gdb_byte *buf_end);
 
+/* If <BUF..BUF_END] contains DW_FORM_block* with just DW_OP_breg*(0) and
+   DW_OP_deref* return the DWARF register number.  Otherwise return -1.
+   DEREF_SIZE_RETURN contains -1 for DW_OP_deref; otherwise it contains the
+   size from DW_OP_deref_size.  */
 int dwarf_block_to_dwarf_reg_deref (const gdb_byte *buf,
 				    const gdb_byte *buf_end,
 				    CORE_ADDR *deref_size_return);
 
+/* If <BUF..BUF_END] contains DW_FORM_block* with single DW_OP_fbreg(X) fill
+   in FB_OFFSET_RETURN with the X offset and return 1.  Otherwise return 0.  */
 int dwarf_block_to_fb_offset (const gdb_byte *buf, const gdb_byte *buf_end,
 			      CORE_ADDR *fb_offset_return);
 
+/* If <BUF..BUF_END] contains DW_FORM_block* with single DW_OP_bregSP(X) fill
+   in SP_OFFSET_RETURN with the X offset and return 1.  Otherwise return 0.
+   The matched SP register number depends on GDBARCH.  */
 int dwarf_block_to_sp_offset (struct gdbarch *gdbarch, const gdb_byte *buf,
 			      const gdb_byte *buf_end,
 			      CORE_ADDR *sp_offset_return);
@@ -193,14 +239,17 @@ gdb_skip_leb128 (const gdb_byte *buf, const gdb_byte *buf_end)
   return buf + bytes_read;
 }
 
+/* Helper to read a uleb128 value or throw an error.  */
 extern const gdb_byte *safe_read_uleb128 (const gdb_byte *buf,
 					  const gdb_byte *buf_end,
 					  uint64_t *r);
 
+/* Helper to read a uleb128 value or throw an error.  */
 extern const gdb_byte *safe_read_sleb128 (const gdb_byte *buf,
 					  const gdb_byte *buf_end,
 					  int64_t *r);
 
+/* Helper to skip a leb128 value or throw an error.  */
 extern const gdb_byte *safe_skip_leb128 (const gdb_byte *buf,
 					 const gdb_byte *buf_end);
 
-- 
2.17.1


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

* [PATCH v4 19/28] Remove dwarf_expr_context from expr.h interface
  2021-11-05 11:38 [PATCH v4 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (17 preceding siblings ...)
  2021-11-05 11:38 ` [PATCH v4 18/28] Comments cleanup between expr.h and expr.c Zoran Zaric
@ 2021-11-05 11:38 ` Zoran Zaric
  2021-11-05 11:38 ` [PATCH v4 20/28] Move read_addr_from_reg function to frame.c Zoran Zaric
                   ` (8 subsequent siblings)
  27 siblings, 0 replies; 38+ messages in thread
From: Zoran Zaric @ 2021-11-05 11:38 UTC (permalink / raw)
  To: gdb-patches

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

After the switch to the new evaluator implementation, it is now
possible to completely remove the dwarf_expr_context class from the
expr.h interface and encapsulate it inside the expr.c file.

The new interface consists of a new function called dwarf2_evaluate
that takes a DWARF expression stream, initial DWARF stack elements (in
a form of a vector of a struct value objects), evaluation context and
expected result type information. Function returns an evaluation result
in a form of a struct value object.

Currently, there is ever only one initial stack element provided to the
evaluator and that element is always a memory address, so having a
vector of struct value object might seems like an overkill.

In reality this new flexibility allows implementation of a new DWARF
attribute extensions that could provide any number of initial stack
elements to describe any location description or value.

gdb/ChangeLog:

	* dwarf2/expr.c (dwarf2_evaluate): New function.
	(struct dwarf_expr_context): Move from expr.h.
        (class dwarf_entry): Move from expr.h
	(dwarf_expr_context::push_address): Remove function.
	* dwarf2/expr.h (struct dwarf_expr_context): Move to expr.c.
        (class dwarf_entry): Move to expr.c.
        (address_type): Expose function.
	* dwarf2/frame.c (execute_stack_op): Now calls dwarf2_evaluate.
	* dwarf2/loc.c (dwarf2_evaluate_loc_desc_full): Now calls
	dwarf2_evaluate.
	(dwarf2_locexpr_baton_eval): Now calls dwarf2_evaluate.
---
 gdb/dwarf2/expr.c  | 214 +++++++++++++++++++++++++++++++++++----------
 gdb/dwarf2/expr.h  | 165 +++++-----------------------------
 gdb/dwarf2/frame.c |  14 ++-
 gdb/dwarf2/loc.c   |  23 +++--
 4 files changed, 214 insertions(+), 202 deletions(-)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index ec7a8d13dc8..8ebc1dfdfe4 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -285,12 +285,7 @@ write_to_memory (CORE_ADDR address, const gdb_byte *buffer,
 					 length, buffer);
 }
 
-/* Return the type used for DWARF operations where the type is
-   generic in the DWARF spec, the ARCH is a target architecture
-   of the type and ADDR_SIZE is expected size of the address.
-   Only certain sizes are supported.  */
-
-static type *
+type *
 address_type (gdbarch *arch, int addr_size)
 {
   dwarf_gdbarch_types *types
@@ -408,6 +403,23 @@ class computed_closure : public refcounted_object
   frame_info *m_frame = nullptr;
 };
 
+/* Base class that describes entries found on a DWARF expression
+   evaluation stack.  */
+
+class dwarf_entry
+{
+protected:
+  /* Not expected to be called on it's own.  */
+  dwarf_entry () = default;
+
+public:
+  virtual ~dwarf_entry () = default;
+
+  virtual std::unique_ptr<dwarf_entry> clone () const = 0;
+};
+
+using dwarf_entry_up = std::unique_ptr<dwarf_entry>;
+
 /* Location description entry found on a DWARF expression evaluation
    stack.
 
@@ -2400,11 +2412,130 @@ sect_variable_value (sect_offset sect_off,
 				     type, true);
 }
 
+/* The expression evaluator works with a dwarf_expr_context, describing
+   its current state and its callbacks.  */
+struct dwarf_expr_context
+{
+  /* Create a new context for the expression evaluator.
+
+     We should ever only pass in the PER_OBJFILE and the ADDR_SIZE
+     information should be retrievable from there.  The PER_OBJFILE
+     contains a pointer to the PER_BFD information anyway and the
+     address size information must be the same for the whole BFD.   */
+  dwarf_expr_context (dwarf2_per_objfile *per_objfile,
+		      int addr_size);
+
+  /* Evaluate the expression at ADDR (LEN bytes long) in a given PER_CU
+     FRAME context.  INIT_VALUES vector contains values that are
+     expected to be pushed on a DWARF expression stack before the
+     evaluation.  AS_LVAL defines if the returned struct value is
+     expected to be a value or a location description.  Where TYPE,
+     SUBOBJ_TYPE and SUBOBJ_OFFSET describe expected struct value
+     representation of the evaluation result.  The ADDR_INFO property
+     can be specified to override the range of memory addresses with
+     the passed in buffer.  */
+  struct value *evaluate (const gdb_byte *addr, size_t len, bool as_lval,
+			  dwarf2_per_cu_data *per_cu, frame_info *frame,
+			  std::vector<value *> *init_values,
+			  const property_addr_info *addr_info,
+			  struct type *type, struct type *subobj_type,
+			  LONGEST subobj_offset);
+
+private:
+  /* The stack of DWARF entries.  */
+  std::vector<dwarf_entry_up> m_stack;
+
+  /* Target address size in bytes.  */
+  int m_addr_size;
+
+  /* The current depth of dwarf expression recursion, via DW_OP_call*,
+     DW_OP_fbreg, DW_OP_push_object_address, etc., and the maximum
+     depth we'll tolerate before raising an error.  */
+  int m_recursion_depth = 0, m_max_recursion_depth = 0x100;
+
+  /* We evaluate the expression in the context of this objfile.  */
+  dwarf2_per_objfile *m_per_objfile;
+
+  /* Frame information used for the evaluation.  */
+  frame_info *m_frame = nullptr;
+
+  /* Compilation unit used for the evaluation.  */
+  dwarf2_per_cu_data *m_per_cu = nullptr;
+
+  /* Property address info used for the evaluation.  */
+  const property_addr_info *m_addr_info = nullptr;
+
+  /* Evaluate the expression at ADDR (LEN bytes long).  */
+  void eval (const gdb_byte *addr, size_t len);
+
+  /* Return the type used for DWARF operations where the type is
+     unspecified in the DWARF spec.  Only certain sizes are
+     supported.  */
+  type *address_type () const;
+
+  /* Push ENTRY onto the stack.  */
+  void push (dwarf_entry_up value);
+
+  /* Return true if the expression stack is empty.  */
+  bool stack_empty_p () const;
+
+  /* Pop a top element of the stack and add as a composite piece
+     with an BIT_OFFSET offset and of a BIT_SIZE size.
+
+     If the following top element of the stack is a composite
+     location description, the piece will be added to it.  Otherwise
+     a new composite location description will be created, pushed on
+     the stack and the piece will be added to that composite.  */
+  void add_piece (ULONGEST bit_size, ULONGEST bit_offset);
+
+  /* The engine for the expression evaluator.  Using the context in this
+     object, evaluate the expression between OP_PTR and OP_END.  */
+  void execute_stack_op (const gdb_byte *op_ptr, const gdb_byte *op_end);
+
+  /* Pop the top item off of the stack.  */
+  dwarf_entry_up pop ();
+
+  /* Retrieve the N'th item on the stack.  */
+  dwarf_entry &fetch (int n);
+
+  /* Fetch the result of the expression evaluation in a form of
+     a struct value, where TYPE, SUBOBJ_TYPE and SUBOBJ_OFFSET
+     describe the source level representation of that result.
+     AS_LVAL defines if the fetched struct value is expected to
+     be a value or a location description.  */
+  value *fetch_result (struct type *type, struct type *subobj_type,
+		       LONGEST subobj_offset, bool as_lval);
+
+  /* Return the location expression for the frame base attribute, in
+     START and LENGTH.  The result must be live until the current
+     expression evaluation is complete.  */
+  void get_frame_base (const gdb_byte **start, size_t *length);
+
+  /* Return the base type given by the indicated DIE at DIE_CU_OFF.
+     This can throw an exception if the DIE is invalid or does not
+     represent a base type.  */
+  type *get_base_type (cu_offset die_cu_off);
+
+  /* Execute DW_AT_location expression for the DWARF expression
+     subroutine in the DIE at DIE_CU_OFF in the CU.  Do not touch
+     STACK while it being passed to and returned from the called DWARF
+     subroutine.  */
+  void dwarf_call (cu_offset die_cu_off);
+
+  /* Push on DWARF stack an entry evaluated for DW_TAG_call_site's
+     parameter matching KIND and KIND_U at the caller of specified
+     BATON. If DEREF_SIZE is not -1 then use DW_AT_call_data_value
+     instead of DW_AT_call_value.  */
+  void push_dwarf_reg_entry_value (call_site_parameter_kind kind,
+				   call_site_parameter_u kind_u,
+				   int deref_size);
+};
+
 /* Return the type used for DWARF operations where the type is
    unspecified in the DWARF spec.  Only certain sizes are
    supported.  */
 
-struct type *
+type *
 dwarf_expr_context::address_type () const
 {
   return ::address_type (this->m_per_objfile->objfile->arch (),
@@ -2420,26 +2551,12 @@ dwarf_expr_context::dwarf_expr_context (dwarf2_per_objfile *per_objfile,
 {
 }
 
-/* See expr.h.  */
-
 void
 dwarf_expr_context::push (dwarf_entry_up entry)
 {
   this->m_stack.emplace_back (std::move (entry));
 }
 
-/* See expr.h.  */
-
-void
-dwarf_expr_context::push_address (CORE_ADDR addr, bool in_stack_memory)
-{
-  this->m_stack.emplace_back (std::make_unique<dwarf_memory>
-    (this->m_per_objfile->objfile->arch (), addr, in_stack_memory));
-}
-
-
-/* See expr.h.  */
-
 dwarf_entry_up
 dwarf_expr_context::pop ()
 {
@@ -2451,8 +2568,6 @@ dwarf_expr_context::pop ()
   return entry;
 }
 
-/* See expr.h.  */
-
 dwarf_entry &
 dwarf_expr_context::fetch (int n)
 {
@@ -2463,8 +2578,6 @@ dwarf_expr_context::fetch (int n)
   return *this->m_stack[this->m_stack.size () - (1 + n)];
 }
 
-/* See expr.h.  */
-
 void
 dwarf_expr_context::get_frame_base (const gdb_byte **start,
 				    size_t * length)
@@ -2491,24 +2604,20 @@ dwarf_expr_context::get_frame_base (const gdb_byte **start,
 				   start, length);
 }
 
-/* See expr.h.  */
-
-struct type *
+type *
 dwarf_expr_context::get_base_type (cu_offset die_cu_off)
 {
   if (this->m_per_cu == nullptr)
     return builtin_type (this->m_per_objfile->objfile->arch ())->builtin_int;
 
-  struct type *result = dwarf2_get_die_type (die_cu_off, this->m_per_cu,
-					     this->m_per_objfile);
+  type *result = dwarf2_get_die_type (die_cu_off, this->m_per_cu,
+				      this->m_per_objfile);
 
   if (result == nullptr)
     error (_("Could not find type for operation"));
   return result;
 }
 
-/* See expr.h.  */
-
 void
 dwarf_expr_context::dwarf_call (cu_offset die_cu_off)
 {
@@ -2532,8 +2641,6 @@ dwarf_expr_context::dwarf_call (cu_offset die_cu_off)
   this->eval (block.data, block.size);
 }
 
-/* See expr.h.  */
-
 void
 dwarf_expr_context::push_dwarf_reg_entry_value (call_site_parameter_kind kind,
 						call_site_parameter_u kind_u,
@@ -2580,8 +2687,6 @@ dwarf_expr_context::push_dwarf_reg_entry_value (call_site_parameter_kind kind,
   this->eval (data_src, size);
 }
 
-/* See expr.h.  */
-
 value *
 dwarf_expr_context::fetch_result (struct type *type, struct type *subobj_type,
 				  LONGEST subobj_offset, bool as_lval)
@@ -2607,18 +2712,22 @@ dwarf_expr_context::fetch_result (struct type *type, struct type *subobj_type,
     }
 }
 
-/* See expr.h.  */
-
 value *
 dwarf_expr_context::evaluate (const gdb_byte *addr, size_t len, bool as_lval,
 			      dwarf2_per_cu_data *per_cu, frame_info *frame,
-			      const struct property_addr_info *addr_info,
+			      std::vector<value *> *init_values,
+			      const 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_addr_info = addr_info;
+  gdbarch *arch = this->m_per_objfile->objfile->arch ();
+
+  if (init_values != nullptr)
+    for (value *val : *init_values)
+      push (gdb_value_to_dwarf_entry (arch, val));
 
   eval (addr, len);
   return fetch_result (type, subobj_type, subobj_offset, as_lval);
@@ -2679,16 +2788,12 @@ get_signed_type (struct gdbarch *gdbarch, struct type *type)
     }
 }
 
-/* See expr.h.  */
-
 bool
 dwarf_expr_context::stack_empty_p () const
 {
   return this->m_stack.empty ();
 }
 
-/* See expr.h.  */
-
 void
 dwarf_expr_context::add_piece (ULONGEST bit_size, ULONGEST bit_offset)
 {
@@ -2740,9 +2845,6 @@ dwarf_expr_context::add_piece (ULONGEST bit_size, ULONGEST bit_offset)
   composite->add_piece (std::move (piece), bit_size);
 }
 
-
-/* See expr.h.  */
-
 void
 dwarf_expr_context::eval (const gdb_byte *addr, size_t len)
 {
@@ -2981,8 +3083,6 @@ dwarf_block_to_sp_offset (struct gdbarch *gdbarch, const gdb_byte *buf,
   return 1;
 }
 
-/* See expr.h.  */
-
 void
 dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 				      const gdb_byte *op_end)
@@ -3940,6 +4040,24 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
   gdb_assert (this->m_recursion_depth >= 0);
 }
 
+/* See expr.h.  */
+
+value *
+dwarf2_evaluate (const gdb_byte *addr, size_t len, bool as_lval,
+		 dwarf2_per_objfile *per_objfile, dwarf2_per_cu_data *per_cu,
+		 frame_info *frame, int addr_size,
+		 std::vector<value *> *init_values,
+		 const property_addr_info *addr_info,
+		 struct type *type, struct type *subobj_type,
+		 LONGEST subobj_offset)
+{
+  dwarf_expr_context ctx (per_objfile, addr_size);
+
+  return ctx.evaluate (addr, len, as_lval, per_cu,
+		       frame, init_values, addr_info,
+		       type, subobj_type, subobj_offset);
+}
+
 void _initialize_dwarf2expr ();
 void
 _initialize_dwarf2expr ()
diff --git a/gdb/dwarf2/expr.h b/gdb/dwarf2/expr.h
index aa371e4bda6..df097f8867d 100644
--- a/gdb/dwarf2/expr.h
+++ b/gdb/dwarf2/expr.h
@@ -25,150 +25,31 @@
 #include "leb128.h"
 #include "gdbtypes.h"
 
-/* Base class that describes entries found on a DWARF expression
-   evaluation stack.  */
-
-class dwarf_entry
-{
-protected:
-  /* Not expected to be called on it's own.  */
-  dwarf_entry () = default;
-
-public:
-  virtual ~dwarf_entry () = default;
-
-  virtual std::unique_ptr<dwarf_entry> clone () const = 0;
-};
-
-using dwarf_entry_up = std::unique_ptr<dwarf_entry>;
-
 struct dwarf2_per_objfile;
 
-/* The expression evaluator works with a dwarf_expr_context, describing
-   its current state and its callbacks.  */
-struct dwarf_expr_context
-{
-  /* Create a new context for the expression evaluator.
-
-     We should ever only pass in the PER_OBJFILE and the ADDR_SIZE
-     information should be retrievable from there.  The PER_OBJFILE
-     contains a pointer to the PER_BFD information anyway and the
-     address size information must be the same for the whole BFD.  */
-  dwarf_expr_context (dwarf2_per_objfile *per_objfile, int addr_size);
-
-  virtual ~dwarf_expr_context () = default;
-
-  /* Push ADDR onto the stack.  */
-  void push_address (CORE_ADDR addr, bool in_stack_memory);
-
-  /* Evaluate the expression at ADDR (LEN bytes long) in a given PER_CU
-     and FRAME context.
-
-     AS_LVAL defines if the returned struct value is expected to be a
-     value (false) or a location description (true).
-
-     TYPE, SUBOBJ_TYPE and SUBOBJ_OFFSET describe the expected struct
-     value representation of the evaluation result.
-
-     The ADDR_INFO property can be specified to override the range of
-     memory addresses with the passed in buffer.  */
-  value *evaluate (const gdb_byte *addr, size_t len, bool as_lval,
-		   dwarf2_per_cu_data *per_cu, frame_info *frame,
-		   const struct property_addr_info *addr_info = nullptr,
-		   struct type *type = nullptr,
-		   struct type *subobj_type = nullptr,
-		   LONGEST subobj_offset = 0);
-
-private:
-  /* The stack of DWARF entries.  */
-  std::vector<dwarf_entry_up> m_stack;
-
-  /* Target address size in bytes.  */
-  int m_addr_size = 0;
-
-  /* The current depth of dwarf expression recursion, via DW_OP_call*,
-     DW_OP_fbreg, DW_OP_push_object_address, etc., and the maximum
-     depth we'll tolerate before raising an error.  */
-  int m_recursion_depth = 0, m_max_recursion_depth = 0x100;
-
-  /* We evaluate the expression in the context of this objfile.  */
-  dwarf2_per_objfile *m_per_objfile;
-
-  /* Frame information used for the evaluation.  */
-  frame_info *m_frame = nullptr;
-
-  /* Compilation unit used for the evaluation.  */
-  dwarf2_per_cu_data *m_per_cu = nullptr;
-
-  /* Property address info used for the evaluation.  */
-  const struct property_addr_info *m_addr_info = nullptr;
-
-  /* Evaluate the expression at ADDR (LEN bytes long).  */
-  void eval (const gdb_byte *addr, size_t len);
-
-  /* Return the type used for DWARF operations where the type is
-     unspecified in the DWARF spec.  Only certain sizes are
-     supported.  */
-  struct type *address_type () const;
-
-  /* Push ENTRY onto the stack.  */
-  void push (dwarf_entry_up entry);
-
-  /* Return true if the expression stack is empty.  */
-  bool stack_empty_p () const;
-
-  /* Pop a top element of the stack and add as a composite piece
-     with an BIT_OFFSET offset and of a BIT_SIZE size.
-
-     If the following top element of the stack is a composite
-     location description, the piece will be added to it.  Otherwise
-     a new composite location description will be created, pushed on
-     the stack and the piece will be added to that composite.  */
-  void add_piece (ULONGEST bit_size, ULONGEST bit_offset);
-
-  /* The engine for the expression evaluator.  Using the context in
-      this object, evaluate the expression between OP_PTR and
-      OP_END.  */
-  void execute_stack_op (const gdb_byte *op_ptr, const gdb_byte *op_end);
-
-  /* Pop the top item off of the stack.  */
-  dwarf_entry_up pop ();
-
-  /* Retrieve the N'th item on the stack.  */
-  dwarf_entry &fetch (int n);
-
-  /* Fetch the result of the expression evaluation in a form of
-     a struct value, where TYPE, SUBOBJ_TYPE and SUBOBJ_OFFSET
-     describe the source level representation of that result.
-     AS_LVAL defines if the fetched struct value is expected to
-     be a value or a location description.  */
-  value *fetch_result (struct type *type, struct type *subobj_type,
-		       LONGEST subobj_offset, bool as_lval);
-
-  /* Return the location expression for the frame base attribute, in
-     START and LENGTH.  The result must be live until the current
-     expression evaluation is complete.  */
-  void get_frame_base (const gdb_byte **start, size_t *length);
-
-  /* Return the base type given by the indicated DIE at DIE_CU_OFF.
-     This can throw an exception if the DIE is invalid or does not
-     represent a base type.  */
-  struct type *get_base_type (cu_offset die_cu_off);
-
-  /* Execute DW_AT_location expression for the DWARF expression
-     subroutine in the DIE at DIE_CU_OFF in the CU.  Do not touch
-     STACK while it being passed to and returned from the called DWARF
-     subroutine.  */
-  void dwarf_call (cu_offset die_cu_off);
-
-  /* Push on DWARF stack an entry evaluated for DW_TAG_call_site's
-     parameter matching KIND and KIND_U at the caller of specified BATON.
-     If DEREF_SIZE is not -1 then use DW_AT_call_data_value instead of
-     DW_AT_call_value.  */
-  void push_dwarf_reg_entry_value (call_site_parameter_kind kind,
-				   call_site_parameter_u kind_u,
-				   int deref_size);
-};
+/* Evaluate the expression at ADDR (LEN bytes long) in a given PER_CU
+   FRAME context.  The PER_OBJFILE contains a pointer to the PER_BFD
+   information.  ADDR_SIZE defines a size of the DWARF generic type.
+   INIT_VALUES vector contains values that are expected to be pushed
+   on a DWARF expression stack before the evaluation.  AS_LVAL defines
+   if the returned struct value is expected to be a value or a location
+   description.  Where TYPE, SUBOBJ_TYPE and SUBOBJ_OFFSET describe
+   expected struct value representation of the evaluation result.  The
+   ADDR_INFO property can be specified to override the range of memory
+   addresses with the passed in buffer.  */
+value *dwarf2_evaluate (const gdb_byte *addr, size_t len, bool as_lval,
+			dwarf2_per_objfile *per_objfile,
+			dwarf2_per_cu_data *per_cu,
+			frame_info *frame, int addr_size,
+			std::vector<value *> *init_values,
+			const struct property_addr_info *addr_info,
+			struct type *type = nullptr,
+			struct type *subobj_type = nullptr,
+			LONGEST subobj_offset = 0);
+
+/* Return the address type used of the ARCH architecture and
+   ADDR_SIZE is expected size of the type.  */
+type *address_type (gdbarch *arch, int addr_size);
 
 /* Return the value of register number REG (a DWARF register number),
    read as an address in a given FRAME.  */
diff --git a/gdb/dwarf2/frame.c b/gdb/dwarf2/frame.c
index f3d38771708..f97387a9d71 100644
--- a/gdb/dwarf2/frame.c
+++ b/gdb/dwarf2/frame.c
@@ -229,11 +229,19 @@ execute_stack_op (const gdb_byte *exp, ULONGEST len, int addr_size,
 		  struct frame_info *this_frame, CORE_ADDR initial,
 		  int initial_in_stack_memory, dwarf2_per_objfile *per_objfile)
 {
-  dwarf_expr_context ctx (per_objfile, addr_size);
   scoped_value_mark free_values;
+  struct type *type = address_type (per_objfile->objfile->arch (),
+				    addr_size);
 
-  ctx.push_address (initial, initial_in_stack_memory);
-  value *result_val = ctx.evaluate (exp, len, true, nullptr, this_frame);
+  value *init_value = value_at_lazy (type, initial);
+  std::vector<value *> init_values;
+
+  set_value_stack (init_value, initial_in_stack_memory);
+  init_values.push_back (init_value);
+
+  value *result_val
+    = dwarf2_evaluate (exp, len, true, per_objfile, nullptr,
+		       this_frame, addr_size, &init_values, nullptr);
 
   if (VALUE_LVAL (result_val) == lval_memory)
     return value_address (result_val);
diff --git a/gdb/dwarf2/loc.c b/gdb/dwarf2/loc.c
index eb128fa5fc6..753ebbbae6c 100644
--- a/gdb/dwarf2/loc.c
+++ b/gdb/dwarf2/loc.c
@@ -1474,15 +1474,15 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame,
   if (size == 0)
     return allocate_optimized_out_value (subobj_type);
 
-  dwarf_expr_context ctx (per_objfile, per_cu->addr_size ());
-
   value *retval;
   scoped_value_mark free_values;
 
   try
     {
-      retval = ctx.evaluate (data, size, as_lval, per_cu, frame, nullptr,
-			     type, subobj_type, subobj_byte_offset);
+      retval
+	= dwarf2_evaluate (data, size, as_lval, per_objfile, per_cu,
+			   frame, per_cu->addr_size (), nullptr, nullptr,
+			   type, subobj_type, subobj_byte_offset);
     }
   catch (const gdb_exception_error &ex)
     {
@@ -1553,23 +1553,28 @@ 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 ());
 
   value *result;
   scoped_value_mark free_values;
+  std::vector<value *> init_values;
 
   if (push_initial_value)
     {
+      struct type *type = address_type (per_objfile->objfile->arch (),
+					per_cu->addr_size ());
+
       if (addr_stack != nullptr)
-	ctx.push_address (addr_stack->addr, false);
+	init_values.push_back (value_at_lazy (type, addr_stack->addr));
       else
-	ctx.push_address (0, false);
+	init_values.push_back (value_at_lazy (type, 0));
     }
 
   try
     {
-      result = ctx.evaluate (dlbaton->data, dlbaton->size,
-			     true, per_cu, frame, addr_stack);
+      result
+	= dwarf2_evaluate (dlbaton->data, dlbaton->size, true, per_objfile,
+			   per_cu, frame, per_cu->addr_size (), &init_values,
+			   addr_stack);
     }
   catch (const gdb_exception_error &ex)
     {
-- 
2.17.1


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

* [PATCH v4 20/28] Move read_addr_from_reg function to frame.c
  2021-11-05 11:38 [PATCH v4 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (18 preceding siblings ...)
  2021-11-05 11:38 ` [PATCH v4 19/28] Remove dwarf_expr_context from expr.h interface Zoran Zaric
@ 2021-11-05 11:38 ` Zoran Zaric
  2021-11-05 11:38 ` [PATCH v4 21/28] Add frame info check to DW_OP_reg operations Zoran Zaric
                   ` (7 subsequent siblings)
  27 siblings, 0 replies; 38+ messages in thread
From: Zoran Zaric @ 2021-11-05 11:38 UTC (permalink / raw)
  To: gdb-patches

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

read_addr_from_reg function is now only called from frame.c file, this
means that the function can safely be moved there.

gdb/ChangeLog:

	* dwarf2/expr.c (read_addr_from_reg): Move function to frame.c.
	* dwarf2/expr.h (read_addr_from_reg): Remove function.
	* dwarf2/frame.c (read_addr_from_reg): Add function from
	expr.c.
---
 gdb/dwarf2/expr.c  | 11 -----------
 gdb/dwarf2/expr.h  |  4 ----
 gdb/dwarf2/frame.c | 12 ++++++++++++
 3 files changed, 12 insertions(+), 15 deletions(-)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index 8ebc1dfdfe4..15164babdd6 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -104,17 +104,6 @@ ill_formed_expression ()
   error (_("Ill-formed DWARF expression"));
 }
 
-/* See expr.h.  */
-
-CORE_ADDR
-read_addr_from_reg (frame_info *frame, int reg)
-{
-  struct gdbarch *gdbarch = get_frame_arch (frame);
-  int regnum = dwarf_reg_to_regnum_or_error (gdbarch, reg);
-
-  return address_from_register (regnum, frame);
-}
-
 /* Read register REGNUM's contents in a given FRAME context.
 
    The data read is offsetted by OFFSET, and the number of bytes read
diff --git a/gdb/dwarf2/expr.h b/gdb/dwarf2/expr.h
index df097f8867d..955fc84f441 100644
--- a/gdb/dwarf2/expr.h
+++ b/gdb/dwarf2/expr.h
@@ -51,10 +51,6 @@ value *dwarf2_evaluate (const gdb_byte *addr, size_t len, bool as_lval,
    ADDR_SIZE is expected size of the type.  */
 type *address_type (gdbarch *arch, int addr_size);
 
-/* Return the value of register number REG (a DWARF register number),
-   read as an address in a given FRAME.  */
-CORE_ADDR read_addr_from_reg (frame_info *frame, int reg);
-
 /* Check that the current operator is either at the end of an
    expression, or that it is followed by a composition operator or by
    DW_OP_GNU_uninit (which should terminate the expression).  */
diff --git a/gdb/dwarf2/frame.c b/gdb/dwarf2/frame.c
index f97387a9d71..e17b36e243b 100644
--- a/gdb/dwarf2/frame.c
+++ b/gdb/dwarf2/frame.c
@@ -193,6 +193,18 @@ dwarf2_frame_state::dwarf2_frame_state (CORE_ADDR pc_, struct dwarf2_cie *cie)
 {
 }
 
+/* Return the value of register number REG (a DWARF register number),
+   read as an address in a given FRAME.  */
+
+static CORE_ADDR
+read_addr_from_reg (frame_info *frame, int reg)
+{
+  gdbarch *arch = get_frame_arch (frame);
+  int regnum = dwarf_reg_to_regnum_or_error (arch, reg);
+
+  return address_from_register (regnum, frame);
+}
+
 /* Execute the required actions for both the DW_CFA_restore and
 DW_CFA_restore_extended instructions.  */
 static void
-- 
2.17.1


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

* [PATCH v4 21/28] Add frame info check to DW_OP_reg operations
  2021-11-05 11:38 [PATCH v4 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (19 preceding siblings ...)
  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 ` Zoran Zaric
  2021-11-05 11:38 ` [PATCH v4 22/28] Remove DWARF expression composition check Zoran Zaric
                   ` (6 subsequent siblings)
  27 siblings, 0 replies; 38+ messages in thread
From: Zoran Zaric @ 2021-11-05 11:38 UTC (permalink / raw)
  To: gdb-patches

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

After enabling location description to be on a DWARF stack, it is now
needed to check the frame context information validity when creating a
register location description.

gdb/ChangeLog:

	* dwarf2/expr.c (dwarf_expr_context::execute_stack_op): Add
	check_frame_info call for DW_OP_reg operations.
---
 gdb/dwarf2/expr.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index 15164babdd6..2555f9969ef 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -3296,6 +3296,7 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 	case DW_OP_reg31:
 	case DW_OP_regx:
 	  {
+	    ensure_have_frame (this->m_frame, "DW_OP_reg");
 	    ULONGEST result;
 
 	    if (op == DW_OP_regx)
-- 
2.17.1


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

* [PATCH v4 22/28] Remove DWARF expression composition check
  2021-11-05 11:38 [PATCH v4 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (20 preceding siblings ...)
  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 ` Zoran Zaric
  2021-11-05 11:38 ` [PATCH v4 23/28] Add support for any location description in CFI Zoran Zaric
                   ` (5 subsequent siblings)
  27 siblings, 0 replies; 38+ messages in thread
From: Zoran Zaric @ 2021-11-05 11:38 UTC (permalink / raw)
  To: gdb-patches

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

The dwarf_expr_require_composition function reports an error if the
last operation is not a leaf node of the DWARF expression. This was
previously used to prevent location description operations to be used
freely in the DWARF expression.

With the new approach, all operations are treated the same and
everything is composable, so there is no need for the previous
restrictions in the expression evaluator.

gdb/ChangeLog:

	* dwarf2/expr.c (dwarf_expr_context::execute_stack_op): Remove
	the use of dwarf_expr_require_composition.
---
 gdb/dwarf2/expr.c | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index 2555f9969ef..676e0bae8a7 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -3308,7 +3308,6 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 	    else
 	      result = op - DW_OP_reg0;
 
-	    dwarf_expr_require_composition (op_ptr, op_end, "DW_OP_reg");
 	    push (make_unique<dwarf_register> (arch, result));
 	    break;
 	  }
@@ -3324,8 +3323,6 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 		    (arch, gdb::array_view<const gdb_byte> (op_ptr, len),
 		     BFD_ENDIAN_UNKNOWN));
 	    op_ptr += len;
-	    dwarf_expr_require_composition (op_ptr, op_end,
-					    "DW_OP_implicit_value");
 	    break;
 	  }
 
@@ -3337,9 +3334,6 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 	    push (make_unique<dwarf_implicit>
 		    (arch, value->contents (),
 		     type_byte_order (value->type ())));
-
-	    dwarf_expr_require_composition (op_ptr, op_end,
-					    "DW_OP_stack_value");
 	    break;
 	  }
 
@@ -3364,8 +3358,6 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 						       this->m_per_cu,
 						       this->m_addr_size,
 						       die_offset, len));
-	    dwarf_expr_require_composition (op_ptr, op_end,
-					    "DW_OP_implicit_pointer");
 	    break;
 	  }
 
-- 
2.17.1


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

* [PATCH v4 23/28] Add support for any location description in CFI
  2021-11-05 11:38 [PATCH v4 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (21 preceding siblings ...)
  2021-11-05 11:38 ` [PATCH v4 22/28] Remove DWARF expression composition check Zoran Zaric
@ 2021-11-05 11:38 ` Zoran Zaric
  2021-11-05 11:38 ` [PATCH v4 24/28] Add DWARF operations for byte and bit offset Zoran Zaric
                   ` (4 subsequent siblings)
  27 siblings, 0 replies; 38+ messages in thread
From: Zoran Zaric @ 2021-11-05 11:38 UTC (permalink / raw)
  To: gdb-patches

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

One of the main benefits of allowing location description to be on the
DWARF stack is that now CFI expression based register rules can be
defined using a location description operations. This allows a register
of one frame to be saved in any location, including any composite
location.

To fully support this feature, the execute_stack_op function in
dwarf2/frame.c needs to return a single struct value object instead of
just an address.

Function put_frame_register_bytes also needs to change to support any
location description.

This support is a one of the key features to truly support optimized
code.

gdb/ChangeLog:

	* dwarf2/frame.c (execute_stack_op): Change to return a struct
	value object.
	(dwarf2_frame_cache): Change to call new execute_stack_op
	definition.
	(dwarf2_frame_prev_register): Change to call new execute_stack_op
	definition.
	* frame.c (put_frame_register_bytes): Add support for writing to
	composite location description.
---
 gdb/dwarf2/frame.c | 54 ++++++++++++++++++++++++++--------------------
 gdb/frame.c        | 31 ++++++++++++++++++++++----
 2 files changed, 58 insertions(+), 27 deletions(-)

diff --git a/gdb/dwarf2/frame.c b/gdb/dwarf2/frame.c
index e17b36e243b..e70dcd5a86e 100644
--- a/gdb/dwarf2/frame.c
+++ b/gdb/dwarf2/frame.c
@@ -236,16 +236,17 @@ register %s (#%d) at %s"),
     }
 }
 
-static CORE_ADDR
+static value *
 execute_stack_op (const gdb_byte *exp, ULONGEST len, int addr_size,
 		  struct frame_info *this_frame, CORE_ADDR initial,
-		  int initial_in_stack_memory, dwarf2_per_objfile *per_objfile)
+		  int initial_in_stack_memory, dwarf2_per_objfile *per_objfile,
+		  struct type* type = nullptr, bool as_lval = true)
 {
   scoped_value_mark free_values;
-  struct type *type = address_type (per_objfile->objfile->arch (),
-				    addr_size);
+  struct type *init_type = address_type (per_objfile->objfile->arch (),
+					 addr_size);
 
-  value *init_value = value_at_lazy (type, initial);
+  value *init_value = value_at_lazy (init_type, initial);
   std::vector<value *> init_values;
 
   set_value_stack (init_value, initial_in_stack_memory);
@@ -255,10 +256,15 @@ execute_stack_op (const gdb_byte *exp, ULONGEST len, int addr_size,
     = dwarf2_evaluate (exp, len, true, per_objfile, nullptr,
 		       this_frame, addr_size, &init_values, nullptr);
 
-  if (VALUE_LVAL (result_val) == lval_memory)
-    return value_address (result_val);
-  else
-    return value_as_address (result_val);
+  /* We need to clean up all the values that are not needed any more.
+     The problem with a value_ref_ptr class is that it disconnects the
+     RETVAL from the value garbage collection, so we need to make
+     a copy of that value on the stack to keep everything consistent.
+     The value_ref_ptr will clean up after itself at the end of this block.  */
+  value_ref_ptr value_holder = value_ref_ptr::new_reference (result_val);
+  free_values.free_to_mark ();
+
+  return value_copy (result_val);
 }
 \f
 
@@ -989,10 +995,14 @@ dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache)
 	  break;
 
 	case CFA_EXP:
-	  cache->cfa =
-	    execute_stack_op (fs.regs.cfa_exp, fs.regs.cfa_exp_len,
-			      cache->addr_size, this_frame, 0, 0,
-			      cache->per_objfile);
+	  {
+	    struct value *value
+	      = execute_stack_op (fs.regs.cfa_exp, fs.regs.cfa_exp_len,
+				  cache->addr_size, this_frame, 0, 0,
+				  cache->per_objfile);
+	    cache->cfa = value_address (value);
+	  }
+
 	  break;
 
 	default:
@@ -1190,24 +1200,22 @@ dwarf2_frame_prev_register (struct frame_info *this_frame, void **this_cache,
       return frame_unwind_got_register (this_frame, regnum, realnum);
 
     case DWARF2_FRAME_REG_SAVED_EXP:
-      addr = execute_stack_op (cache->reg[regnum].loc.exp.start,
+      return execute_stack_op (cache->reg[regnum].loc.exp.start,
 			       cache->reg[regnum].loc.exp.len,
-			       cache->addr_size,
-			       this_frame, cache->cfa, 1,
-			       cache->per_objfile);
-      return frame_unwind_got_memory (this_frame, regnum, addr);
+			       cache->addr_size, this_frame,
+			       cache->cfa, 1, cache->per_objfile,
+			       register_type (gdbarch, regnum));
 
     case DWARF2_FRAME_REG_SAVED_VAL_OFFSET:
       addr = cache->cfa + cache->reg[regnum].loc.offset;
       return frame_unwind_got_constant (this_frame, regnum, addr);
 
     case DWARF2_FRAME_REG_SAVED_VAL_EXP:
-      addr = execute_stack_op (cache->reg[regnum].loc.exp.start,
+      return execute_stack_op (cache->reg[regnum].loc.exp.start,
 			       cache->reg[regnum].loc.exp.len,
-			       cache->addr_size,
-			       this_frame, cache->cfa, 1,
-			       cache->per_objfile);
-      return frame_unwind_got_constant (this_frame, regnum, addr);
+			       cache->addr_size, this_frame,
+			       cache->cfa, 1, cache->per_objfile,
+			       register_type (gdbarch, regnum), false);
 
     case DWARF2_FRAME_REG_UNSPECIFIED:
       /* GCC, in its infinite wisdom decided to not provide unwind
diff --git a/gdb/frame.c b/gdb/frame.c
index 2a899fc494f..3dd6c799847 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -1534,19 +1534,42 @@ put_frame_register_bytes (struct frame_info *frame, int regnum,
     {
       int curr_len = register_size (gdbarch, regnum) - offset;
 
+      struct value *value = frame_unwind_register_value (frame->next,
+							 regnum);
+
       if (curr_len > len)
 	curr_len = len;
 
       const gdb_byte *myaddr = buffer.data ();
-      if (curr_len == register_size (gdbarch, regnum))
+
+      /*  Computed value is a special case.  The computed callback
+	  mechanism requires a strut value argument, so we need to
+	  make one.  */
+      if (value != nullptr && VALUE_LVAL (value) == lval_computed)
+	{
+	  const lval_funcs *funcs = value_computed_funcs (value);
+
+	  if (funcs->write == nullptr)
+	    error (_("Attempt to assign to an unmodifiable value."));
+
+	  type * reg_type = register_type (gdbarch, regnum);
+
+	  struct value *from_value = allocate_value (reg_type);
+	  memcpy (value_contents_raw (from_value), myaddr,
+		  TYPE_LENGTH (reg_type));
+
+	  set_value_offset (value, offset);
+
+	  funcs->write (value, from_value);
+	  release_value (from_value);
+	}
+      else if (curr_len == register_size (gdbarch, regnum))
 	{
 	  put_frame_register (frame, regnum, myaddr);
 	}
       else
 	{
-	  struct value *value = frame_unwind_register_value (frame->next,
-							     regnum);
-	  gdb_assert (value != NULL);
+	  gdb_assert (value != nullptr);
 
 	  memcpy ((char *) value_contents_writeable (value).data () + offset,
 		  myaddr, curr_len);
-- 
2.17.1


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

* [PATCH v4 24/28] Add DWARF operations for byte and bit offset
  2021-11-05 11:38 [PATCH v4 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (22 preceding siblings ...)
  2021-11-05 11:38 ` [PATCH v4 23/28] Add support for any location description in CFI Zoran Zaric
@ 2021-11-05 11:38 ` Zoran Zaric
  2021-11-05 11:38 ` [PATCH v4 25/28] Add support for DW_OP_LLVM_undefined operation Zoran Zaric
                   ` (3 subsequent siblings)
  27 siblings, 0 replies; 38+ messages in thread
From: Zoran Zaric @ 2021-11-05 11:38 UTC (permalink / raw)
  To: gdb-patches

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

Currently in DWARF, there are only two ways to specify an offset for a
location description.

For a memory location description, the location description can be
first converted to a DWARF value, after which an arithmetic operation
can be applied to it. This however, only works while there are no
address spaces involved, that are not mapped to a general address space
(CORE_ADDR). Another limitation is that there is no way to specify a
bit offset to that location description.

Second way of specifying an offset to a location description is more
universal and involves wrapping that location description in a
composite piece, where piece itself has a bit/byte offset defined. The
problem with this approach is that both DW_OP_piece and DW_OP_bit_piece
define an offset as a DWARF operation operand, which means that an
offset needs to be a constant value encoded into the DWARF expression.

By adding three new operations (DW_OP_LLVM_offset,
DW_OP_LLVM_offset_constu and DW_OP_LLVM_bit_offset) these restrictions
are now lifted.

Detailed descriptions of these new operations can be found here:

https://llvm.org/docs/AMDGPUDwarfExtensionsForHeterogeneousDebugging.html

The same document also explores an idea of extending the
DW_OP_push_object_address operation to allow pushing any location
description on the DWARF stack. This together with the new bit/byte
offset operations, generalizes DWARF to work with bit fields and could
replace the odd passed-in buffer mechanics in a more elegant way.

There seem to be a difference in views on what the big endian machine
register byte ordering should be. On one hand, some would expect for
a register to behave in the same way as memory, but on another, there
seems to be an existing implementation for (IBM big endian based
machines) which seems to be viewing registers differently, depending
if the register location description is part of a composite piece or
not. More on this topic can be found here:

https://sourceware.org/legacy-ml/gdb-patches/2017-04/msg00177.html

Unfortunately, the gdb current implementation favors the second option,
which feels like a target specific implementation.

Because of this, I’ve decided to not favor a specific implementation
in the added test for new DWARF operations (dw2-llvm-offset.exp), so
the test is restricted to only run on little endian platforms.

gdb/ChangeLog:

	* ada-lang.c (coerce_unspec_val_to_type): Add source bit offset
	argument to the value_contents_copy call.
	* compile/compile-loc2c.c (compute_stack_depth_worker): Add new
	DWARF operations support.
	* dwarf2/expr.c (dwarf_register::to_gdb_value): Add bit offset
	support.
        (dwarf_register::to_gdb_value): Add bit offset support.
	(dwarf_register::to_gdb_value): Add source bit
	offset argument to the value_contents_copy call.
	(dwarf_expr_context::execute_stack_op): Add new DWARF
	operations support.
        * dwarf2/loc.c (dwarf2_get_symbol_read_needs): Add new DWARF
        operation support.
        (disassemble_dwarf_expression): Add support for new
        DW_OP_LLVM_offset_constu operation.
	* findvar.c (read_frame_register_value): Add source bit offset
	argument to the value_contents_copy call.
        * frame.c (get_frame_register_bytes): Takes into account a
        potential unwound register struct value offset.
        (get_frame_register_bytes): Takes into account a potential
        unwound register struct value offset.
	* valops.c (read_value_memory): Add bit offset support.
	(value_assign): Add bit offset support.
	(value_repeat): Add bit offset support.
	(value_array): Add source bit offset argument to the
	value_contents_copy call.
	(value_slice): Add source bit offset argument to the
	value_contents_copy call.
	* value.c (value_contents_copy_raw): Add source bit offset
	support.
	(value_contents_copy): Add source bit offset argument to
	value_contents_copy_raw call.
	(value_primitive_field): Add source bit offset argument to the
	value_contents_copy call.
	(value_from_component): Add source bit offset argument to the
	value_contents_copy call.
	(value_fetch_lazy_memory): Add bit offset argument to the
	read_value_memory call.
	(value_fetch_lazy_register): Add source bit offset argument to
	the value_contents_copy call.
	* value.h (value_contents_copy): Add source bit offset
	argument.

include/ChangeLog:

	* dwarf2.def (DW_OP_DUP): New DWARF operations enumeration.

gdb/testsuite/ChangeLog:

	* lib/dwarf.exp: Add support for new DW_OP_LLVM_offset_constu
	DWARF operation.
	* gdb.dwarf2/dw2-llvm-offset.exp: New test.
---
 gdb/ada-lang.c                               |   2 +-
 gdb/compile/compile-loc2c.c                  |   6 +
 gdb/dwarf2/expr.c                            |  40 ++-
 gdb/dwarf2/loc.c                             |   8 +
 gdb/f-lang.c                                 |   6 +-
 gdb/findvar.c                                |   4 +-
 gdb/frame.c                                  |  20 +-
 gdb/testsuite/gdb.dwarf2/dw2-llvm-offset.exp | 328 +++++++++++++++++++
 gdb/testsuite/lib/dwarf.exp                  |   4 +
 gdb/valops.c                                 | 131 +++++---
 gdb/value.c                                  |  68 ++--
 gdb/value.h                                  |   2 +-
 include/dwarf2.def                           |   4 +
 13 files changed, 541 insertions(+), 82 deletions(-)
 create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-llvm-offset.exp

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index d964dae42cf..8a442e0f5c9 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -531,7 +531,7 @@ coerce_unspec_val_to_type (struct value *val, struct type *type)
       else
 	{
 	  result = allocate_value (type);
-	  value_contents_copy (result, 0, val, 0, TYPE_LENGTH (type));
+	  value_contents_copy (result, 0, val, 0, 0, TYPE_LENGTH (type));
 	}
       set_value_component_location (result, val);
       set_value_bitsize (result, value_bitsize (val));
diff --git a/gdb/compile/compile-loc2c.c b/gdb/compile/compile-loc2c.c
index fb1a4ff02b6..77eb5a8e19d 100644
--- a/gdb/compile/compile-loc2c.c
+++ b/gdb/compile/compile-loc2c.c
@@ -357,6 +357,12 @@ compute_stack_depth_worker (int start, int *need_tempvar,
 	  (*info)[offset].label = 1;
 	  break;
 
+	case DW_OP_LLVM_offset:
+	case DW_OP_LLVM_bit_offset:
+	  --stack_depth;
+	  break;
+
+	case DW_OP_LLVM_offset_constu:
 	case DW_OP_nop:
 	  break;
 
diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index 676e0bae8a7..a0310fef7a4 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -1093,6 +1093,7 @@ dwarf_memory::to_gdb_value (frame_info *frame, struct type *type,
     = 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);
+  set_value_bitpos (retval, m_bit_suboffset);
   return retval;
 }
 
@@ -1270,6 +1271,9 @@ dwarf_register::to_gdb_value (frame_info *frame, struct type *type,
   else
     set_value_offset (retval, (retval_offset + m_offset) / unit_size);
 
+  set_value_bitpos (retval,
+		    m_bit_suboffset + (m_offset % unit_size) * HOST_CHAR_BIT);
+
   /* Get the data.  */
   read_frame_register_value (retval, frame);
 
@@ -1281,7 +1285,7 @@ dwarf_register::to_gdb_value (frame_info *frame, struct type *type,
 	 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));
+      value_contents_copy (temp, 0, retval, 0, 0, TYPE_LENGTH (subobj_type));
       retval = temp;
     }
 
@@ -4013,6 +4017,40 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 	  push (make_unique<dwarf_memory> (arch, this->m_addr_info->addr));
 	  break;
 
+	case DW_OP_LLVM_offset:
+	  {
+	    dwarf_value_up value = to_value (pop (), address_type);
+	    dwarf_require_integral (value->type ());
+	    dwarf_location_up location = to_location (pop (), arch);
+
+	    location->add_bit_offset (value->to_long () * HOST_CHAR_BIT);
+	    push (std::move (location));
+	    break;
+	  }
+
+	case DW_OP_LLVM_offset_constu:
+	  {
+	    uint64_t uoffset;
+	    op_ptr = safe_read_uleb128 (op_ptr, op_end, &uoffset);
+	    ULONGEST result = uoffset;
+	    dwarf_location_up location = to_location (pop (), arch);
+
+	    location->add_bit_offset (result * HOST_CHAR_BIT);
+	    push (std::move (location));
+	    break;
+	  }
+
+	case DW_OP_LLVM_bit_offset:
+	  {
+	    dwarf_value_up value = to_value (pop (), address_type);
+	    dwarf_require_integral (value->type ());
+	    dwarf_location_up location = to_location (pop (), arch);
+
+	    location->add_bit_offset (value->to_long ());
+	    push (std::move (location));
+	    break;
+	  }
+
 	default:
 	  error (_("Unhandled dwarf expression opcode 0x%x"), op);
 	}
diff --git a/gdb/dwarf2/loc.c b/gdb/dwarf2/loc.c
index 753ebbbae6c..7c0782404dd 100644
--- a/gdb/dwarf2/loc.c
+++ b/gdb/dwarf2/loc.c
@@ -1924,6 +1924,8 @@ dwarf2_get_symbol_read_needs (gdb::array_view<const gdb_byte> expr,
 	case DW_OP_nop:
 	case DW_OP_GNU_uninit:
 	case DW_OP_push_object_address:
+	case DW_OP_LLVM_offset:
+	case DW_OP_LLVM_bit_offset:
 	  break;
 
 	case DW_OP_form_tls_address:
@@ -1941,6 +1943,7 @@ dwarf2_get_symbol_read_needs (gdb::array_view<const gdb_byte> expr,
 	case DW_OP_constu:
 	case DW_OP_plus_uconst:
 	case DW_OP_piece:
+	case DW_OP_LLVM_offset_constu:
 	  op_ptr = safe_skip_leb128 (op_ptr, expr_end);
 	  break;
 
@@ -3657,6 +3660,11 @@ disassemble_dwarf_expression (struct ui_file *stream,
 	  data += offset_size;
 	  fprintf_filtered (stream, " offset %s", phex_nz (ul, offset_size));
 	  break;
+
+	case DW_OP_LLVM_offset_constu:
+	  data = safe_read_uleb128 (data, end, &ul);
+	  fprintf_filtered (stream, " %s", pulongest (ul));
+	  break;
 	}
 
       fprintf_filtered (stream, "\n");
diff --git a/gdb/f-lang.c b/gdb/f-lang.c
index 230feb78e26..a50629a4427 100644
--- a/gdb/f-lang.c
+++ b/gdb/f-lang.c
@@ -161,7 +161,7 @@ fortran_bounds_all_dims (bool lbound_p,
       gdb_assert (dst_offset + TYPE_LENGTH (value_type (v))
 		  <= TYPE_LENGTH (value_type (result)));
       gdb_assert (TYPE_LENGTH (value_type (v)) == elm_len);
-      value_contents_copy (result, dst_offset, v, 0, elm_len);
+      value_contents_copy (result, dst_offset, v, 0, 0, elm_len);
 
       /* Peel another dimension of the array.  */
       array_type = TYPE_TARGET_TYPE (array_type);
@@ -289,7 +289,7 @@ class fortran_array_repacker_base_impl
      available offset.  */
   void copy_element_to_dest (struct value *elt)
   {
-    value_contents_copy (m_dest, m_dest_offset, elt, 0,
+    value_contents_copy (m_dest, m_dest_offset, elt, 0, 0,
 			 TYPE_LENGTH (value_type (elt)));
     m_dest_offset += TYPE_LENGTH (value_type (elt));
   }
@@ -736,7 +736,7 @@ fortran_array_shape (struct gdbarch *gdbarch, const language_defn *lang,
       gdb_assert (dst_offset + TYPE_LENGTH (value_type (v))
 		  <= TYPE_LENGTH (value_type (result)));
       gdb_assert (TYPE_LENGTH (value_type (v)) == elm_len);
-      value_contents_copy (result, dst_offset, v, 0, elm_len);
+      value_contents_copy (result, dst_offset, v, 0, 0, elm_len);
 
       /* Peel another dimension of the array.  */
       val_type = TYPE_TARGET_TYPE (val_type);
diff --git a/gdb/findvar.c b/gdb/findvar.c
index d2b77133982..2f97b6079cb 100644
--- a/gdb/findvar.c
+++ b/gdb/findvar.c
@@ -869,6 +869,7 @@ read_frame_register_value (struct value *value, struct frame_info *frame)
   struct gdbarch *gdbarch = get_frame_arch (frame);
   LONGEST offset = 0;
   LONGEST reg_offset = value_offset (value);
+  LONGEST bit_offset = value_bitpos (value);
   int regnum = VALUE_REGNUM (value);
   int len = type_length_units (check_typedef (value_type (value)));
 
@@ -892,7 +893,8 @@ read_frame_register_value (struct value *value, struct frame_info *frame)
       if (reg_len > len)
 	reg_len = len;
 
-      value_contents_copy (value, offset, regval, reg_offset, reg_len);
+      value_contents_copy (value, offset, regval, reg_offset,
+			   bit_offset, reg_len);
 
       offset += reg_len;
       len -= reg_len;
diff --git a/gdb/frame.c b/gdb/frame.c
index 3dd6c799847..051d6f766ce 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -1497,8 +1497,9 @@ get_frame_register_bytes (frame_info *frame, int regnum,
 	      return false;
 	    }
 
-	  memcpy (myaddr, value_contents_all (value).data () + offset,
-		  curr_len);
+	  memcpy (myaddr,
+		  value_contents_all (value).data ()
+		    + value_offset (value) + offset, curr_len);
 	  release_value (value);
 	}
 
@@ -1532,10 +1533,19 @@ put_frame_register_bytes (struct frame_info *frame, int regnum,
   /* Copy the data.  */
   while (len > 0)
     {
-      int curr_len = register_size (gdbarch, regnum) - offset;
-
       struct value *value = frame_unwind_register_value (frame->next,
 							 regnum);
+      /* Need to account the unwind register offset too.  */
+      offset += value == NULL ? 0 : value_offset (value);
+
+      if (offset >= register_size (gdbarch, regnum))
+	{
+	  offset -= register_size (gdbarch, regnum);
+	  regnum++;
+	  continue;
+	}
+
+      int curr_len = register_size (gdbarch, regnum) - offset;
 
       if (curr_len > len)
 	curr_len = len;
@@ -1555,7 +1565,7 @@ put_frame_register_bytes (struct frame_info *frame, int regnum,
 	  type * reg_type = register_type (gdbarch, regnum);
 
 	  struct value *from_value = allocate_value (reg_type);
-	  memcpy (value_contents_raw (from_value), myaddr,
+	  memcpy (value_contents_raw (from_value).data (), myaddr,
 		  TYPE_LENGTH (reg_type));
 
 	  set_value_offset (value, offset);
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-llvm-offset.exp b/gdb/testsuite/gdb.dwarf2/dw2-llvm-offset.exp
new file mode 100644
index 00000000000..734007ea680
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-llvm-offset.exp
@@ -0,0 +1,328 @@
+# Copyright 2017-2021 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test DWARF operation that allow adding byte and bit offset to any
+# location description.
+#
+# In particular, the test uses memory and register location
+# descriptions (both as standalone and parts of the composite
+# location), and applies different byte and bit offsets to them.
+
+load_lib dwarf.exp
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+if {![dwarf2_support]} {
+    return 0
+}
+
+# Choose suitable integer registers for the test.
+
+set dwarf_regnum 0
+
+if { [is_aarch64_target] } {
+    set regname x0
+} elseif { [is_aarch32_target]
+	   || [istarget "s390*-*-*" ]
+	   || [istarget "powerpc*-*-*"]
+	   || [istarget "rs6000*-*-aix*"] } {
+    set regname r0
+} elseif { [is_x86_like_target] } {
+    set regname eax
+} elseif { [is_amd64_regs_target] } {
+    set regname rax
+} else {
+    verbose "Skipping ${gdb_test_file_name}."
+    return
+}
+
+standard_testfile var-access.c ${gdb_test_file_name}-dw.S
+
+# Make some DWARF for the test.
+
+set asm_file [standard_output_file $srcfile2]
+Dwarf::assemble $asm_file {
+    global dwarf_regnum regname srcdir subdir srcfile
+    set buf_var [gdb_target_symbol buf]
+
+    set main_result [function_range main ${srcdir}/${subdir}/${srcfile}]
+    set main_start [lindex $main_result 0]
+    set main_length [lindex $main_result 1]
+
+    cu {} {
+	DW_TAG_compile_unit {
+	    {DW_AT_name var-access.c}
+	    {DW_AT_comp_dir /tmp}
+	} {
+	    declare_labels char_type_label int_type_label
+	    declare_labels array_size_4_type_label array_size_8_type_label
+
+	    # define char type.
+	    char_type_label: DW_TAG_base_type {
+		{DW_AT_name "char"}
+		{DW_AT_encoding @DW_ATE_signed}
+		{DW_AT_byte_size 1 DW_FORM_sdata}
+	    }
+
+	    # define int type.
+	    int_type_label: DW_TAG_base_type {
+		{DW_AT_name "int"}
+		{DW_AT_encoding @DW_ATE_signed}
+		{DW_AT_byte_size 4 DW_FORM_sdata}
+	    }
+
+	    # define 4 byte size array type.
+	    array_size_4_type_label: DW_TAG_array_type {
+		{DW_AT_type :$char_type_label}
+	    } {
+		DW_TAG_subrange_type {
+		    {DW_AT_type :$int_type_label}
+		    {DW_AT_upper_bound 3 DW_FORM_udata}
+		}
+	    }
+
+	    # define 8 byte size array type.
+	    array_size_8_type_label: DW_TAG_array_type {
+		{DW_AT_type :$char_type_label}
+	    } {
+		DW_TAG_subrange_type {
+		    {DW_AT_type :$int_type_label}
+		    {DW_AT_upper_bound 7 DW_FORM_udata}
+		}
+	    }
+
+	    DW_TAG_subprogram {
+		{DW_AT_name main}
+		{DW_AT_low_pc $main_start addr}
+		{DW_AT_high_pc $main_length data8}
+	    } {
+		# define original buf variable.
+		DW_TAG_variable {
+		    {DW_AT_name buf}
+		    {DW_AT_type :$array_size_4_type_label}
+		    {DW_AT_location {
+			DW_OP_addr $buf_var
+		    } SPECIAL_expr}
+		}
+
+		# defined a variable located in
+		# a third byte of the buf variable.
+		DW_TAG_variable {
+		    {DW_AT_name buf_byte_3}
+		    {DW_AT_type :$char_type_label}
+		    {DW_AT_location {
+			DW_OP_addr $buf_var
+			DW_OP_LLVM_offset_constu 2
+		    } SPECIAL_expr}
+		    {external 1 flag}
+		}
+
+		# defined a variable located in a second byte
+		# of the buf variable with a bit offset of one.
+		DW_TAG_variable {
+		    {DW_AT_name buf_byte_2_bit_1}
+		    {DW_AT_type :$char_type_label}
+		    {DW_AT_location {
+			DW_OP_addr $buf_var
+			DW_OP_lit9
+			DW_OP_LLVM_bit_offset
+		    } SPECIAL_expr}
+		    {external 1 flag}
+		}
+
+		# defined a variable located in a
+		# third byte of the REGNAME register.
+		DW_TAG_variable {
+		    {DW_AT_name reg_byte_3}
+		    {DW_AT_type :$char_type_label}
+		    {DW_AT_location {
+			DW_OP_regx $dwarf_regnum
+			DW_OP_lit2
+			DW_OP_LLVM_offset
+		    } SPECIAL_expr}
+		    {external 1 flag}
+		}
+
+		# defined a variable located in a second byte of
+		# the REGNAME register with a bit offset of one.
+		DW_TAG_variable {
+		    {DW_AT_name reg_byte_2_bit_1}
+		    {DW_AT_type :$char_type_label}
+		    {DW_AT_location {
+			DW_OP_regx $dwarf_regnum
+			DW_OP_lit1
+			DW_OP_LLVM_offset
+			DW_OP_lit1
+			DW_OP_LLVM_bit_offset
+		    } SPECIAL_expr}
+		    {external 1 flag}
+		}
+
+		# Define an array variable spread in different
+		# pieces of buf variable and REGNAME register.
+		DW_TAG_variable {
+		    {DW_AT_name mix_array}
+		    {DW_AT_type :$array_size_8_type_label}
+		    {DW_AT_location {
+
+			# a byte piece located in a
+			# fourth byte of the buf variable.
+			DW_OP_addr $buf_var
+			DW_OP_LLVM_offset_constu 3
+			DW_OP_piece 0x1
+
+			# a byte piece located in a
+			# third byte of the buf variable.
+			DW_OP_addr $buf_var
+			DW_OP_lit2
+			DW_OP_LLVM_offset
+			DW_OP_piece 0x1
+
+			# a byte piece located in a second byte of
+			# the buf variable with a bit offset of one.
+			DW_OP_addr $buf_var
+			DW_OP_lit1
+			DW_OP_LLVM_offset
+			DW_OP_lit1
+			DW_OP_LLVM_bit_offset
+			DW_OP_piece 0x1
+
+			# a four bit piece located in a first byte
+			# of the buf variable with a bit offset of one.
+			DW_OP_addr $buf_var
+			DW_OP_LLVM_offset_constu 0
+			DW_OP_bit_piece 0x4 0x1
+
+			# a four bit piece located in a first byte of
+			# the buf variable with a bit offset of eight.
+			DW_OP_addr $buf_var
+			DW_OP_lit1
+			DW_OP_LLVM_bit_offset
+			DW_OP_LLVM_offset_constu 0
+			DW_OP_bit_piece 0x4 0x7
+
+			# a byte piece located in a fourth
+			# byte of the REGNAME register.
+			DW_OP_regx $dwarf_regnum
+			DW_OP_LLVM_offset_constu 3
+			DW_OP_piece 0x1
+
+			# a byte piece located in a third
+			# byte of the REGNAME register.
+			DW_OP_regx $dwarf_regnum
+			DW_OP_lit2
+			DW_OP_LLVM_offset
+			DW_OP_piece 0x1
+
+			# a byte piece located in a second byte of the
+			# REGNAME register with a bit offset of one.
+			DW_OP_regx $dwarf_regnum
+			DW_OP_lit1
+			DW_OP_LLVM_offset
+			DW_OP_lit1
+			DW_OP_LLVM_bit_offset
+			DW_OP_piece 0x1
+
+			# a four bit piece located in a first byte of
+			# the REGNAME register with a bit offset of one.
+			DW_OP_regx $dwarf_regnum
+			DW_OP_LLVM_offset_constu 0
+			DW_OP_bit_piece 0x4 0x1
+
+			# a four bit piece located in a first byte of the
+			# REGNAME register with a bit offset of eight.
+			DW_OP_regx $dwarf_regnum
+			DW_OP_lit1
+			DW_OP_LLVM_bit_offset
+			DW_OP_LLVM_offset_constu 0
+			DW_OP_bit_piece 0x4 0x7
+
+		    } SPECIAL_expr}
+		    {external 1 flag}
+		}
+	    }
+	}
+    }
+}
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} \
+     [list $srcfile $asm_file] {nodebug}] } {
+    return -1
+}
+
+if ![runto_main] {
+    return -1
+}
+
+# Determine byte order.
+set endian [get_endianness]
+
+if { $endian != "little" } then {
+    verbose "Skipping ${gdb_test_file_name}."
+    return
+}
+
+gdb_test_no_output "set var \$$regname = 0x04030201" "init reg"
+gdb_test_no_output "set var *\(\(unsigned int *\) buf\) = 0x04030201" \
+		   "init buf"
+
+gdb_test "print/x buf_byte_3" " = 0x3" "buf_byte_3 == 0x3"
+gdb_test "print/x buf_byte_2_bit_1" " = 0x81" \
+	 "print buf_byte_2_bit_1"
+gdb_test "print/x reg_byte_3" " = 0x3" "reg_byte_3 == 0x3"
+gdb_test "print/x reg_byte_2_bit_1" " = 0x81" \
+	 "print reg_byte_2_bit_1"
+
+gdb_test_no_output "set var buf_byte_3 = 0x4" "init buf_byte_3 to 0x4"
+gdb_test "print/x buf_byte_3" " = 0x4" "buf_byte_3 == 0x4"
+
+gdb_test_no_output "set var buf_byte_2_bit_1 = 0x4" \
+		   "init buf_byte_2_bit_1 to 0x4"
+gdb_test "print/x buf_byte_2_bit_1" " = 0x4" "buf_byte_2_bit_1 == 0x4"
+
+gdb_test "print/x buf" " = \\{0x1, 0x8, 0x4, 0x4\\}" "buf print"
+
+gdb_test_no_output "set var reg_byte_3 = 0x4" "init reg_byte_3 to 0x4"
+gdb_test "print/x reg_byte_3" " = 0x4" "reg_byte_3 == 0x4"
+
+gdb_test_no_output "set var reg_byte_2_bit_1 = 0x4" \
+		   "init reg_byte_2_bit_1 to 0x4"
+gdb_test "print/x reg_byte_2_bit_1" " = 0x4" "reg_byte_2_bit_1 == 0x4"
+
+gdb_test "print/x \$$regname" " = 0x4040801" "\$$regname print"
+
+gdb_test_no_output "set var \$$regname = 0x04030201" "reset reg"
+gdb_test_no_output "set var *\(\(unsigned int *\) buf\) = 0x04030201" \
+		   "reset buf"
+
+gdb_test "print/x mix_array" \
+	 " = \\{0x4, 0x3, 0x81, 0x20, 0x4, 0x3, 0x81, 0x20\\}" \
+	 "mix_array print"
+
+gdb_test_no_output "set var mix_array\[1\] = 0x4" \
+		   "set mix_array second byte"
+gdb_test_no_output "set var mix_array\[2\] = 0x4" \
+		   "set mix_array third byte"
+gdb_test_no_output "set var mix_array\[5\] = 0x4" \
+		   "set mix_array fifth byte"
+gdb_test_no_output "set var mix_array\[6\] = 0x4" \
+		   "set mix_array sixth byte"
+
+gdb_test "print/x mix_array" \
+	 " = \\{0x4, 0x4, 0x4, 0x80, 0x4, 0x4, 0x4, 0x80\\}" \
+	 "mix_array second print"
+
+gdb_test "print/x buf" " = \\{0x1, 0x8, 0x4, 0x4\\}" "buf second print"
+
+gdb_test "print/x \$$regname" " = 0x4040801" "\$$regname second print"
diff --git a/gdb/testsuite/lib/dwarf.exp b/gdb/testsuite/lib/dwarf.exp
index b48cfad3b9e..48a10aedf26 100644
--- a/gdb/testsuite/lib/dwarf.exp
+++ b/gdb/testsuite/lib/dwarf.exp
@@ -1221,6 +1221,10 @@ namespace eval Dwarf {
 		    _op .sleb128 [lindex $line 1]
 		}
 
+		DW_OP_LLVM_offset_constu {
+		    _op .uleb128 [lindex $line 1]
+		}
+
 		default {
 		    if {[llength $line] > 1} {
 			error "Unimplemented: operands in location for $opcode"
diff --git a/gdb/valops.c b/gdb/valops.c
index 9787cdbb513..a79afa354a7 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -1040,20 +1040,31 @@ read_value_memory (struct value *val, LONGEST bit_offset,
   ULONGEST xfered_total = 0;
   struct gdbarch *arch = get_value_arch (val);
   int unit_size = gdbarch_addressable_memory_unit_size (arch);
+  bool big_endian = type_byte_order (value_type (val)) == BFD_ENDIAN_BIG;
   enum target_object object;
+  size_t extended_length
+    = length + (bit_offset + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT;
+  gdb_byte *buffer_ptr = buffer;
+  gdb::byte_vector temp_buffer;
+
+  if (bit_offset)
+    {
+      temp_buffer.resize (extended_length);
+      buffer_ptr = temp_buffer.data ();
+    }
 
   object = stack ? TARGET_OBJECT_STACK_MEMORY : TARGET_OBJECT_MEMORY;
 
-  while (xfered_total < length)
+  while (xfered_total < extended_length)
     {
       enum target_xfer_status status;
       ULONGEST xfered_partial;
 
       status = target_xfer_partial (current_inferior ()->top_target (),
 				    object, NULL,
-				    buffer + xfered_total * unit_size, NULL,
+				    buffer_ptr + xfered_total * unit_size, NULL,
 				    memaddr + xfered_total,
-				    length - xfered_total,
+				    extended_length - xfered_total,
 				    &xfered_partial);
 
       if (status == TARGET_XFER_OK)
@@ -1070,6 +1081,10 @@ read_value_memory (struct value *val, LONGEST bit_offset,
       xfered_total += xfered_partial;
       QUIT;
     }
+
+  if (bit_offset)
+    copy_bitwise (buffer, 0, temp_buffer.data (),
+		  bit_offset, length * HOST_CHAR_BIT, big_endian);
 }
 
 /* Store the contents of FROMVAL into the location of TOVAL.
@@ -1141,7 +1156,7 @@ value_assign (struct value *toval, struct value *fromval)
 	const gdb_byte *dest_buffer;
 	CORE_ADDR changed_addr;
 	int changed_len;
-	gdb_byte buffer[sizeof (LONGEST)];
+	gdb::byte_vector buffer;
 
 	if (value_bitsize (toval))
 	  {
@@ -1167,10 +1182,26 @@ value_assign (struct value *toval, struct value *fromval)
 		       "don't fit in a %d bit word."),
 		     (int) sizeof (LONGEST) * HOST_CHAR_BIT);
 
-	    read_memory (changed_addr, buffer, changed_len);
-	    modify_field (type, buffer, value_as_long (fromval),
+	    buffer.resize (changed_len);
+
+	    read_memory (changed_addr, buffer.data (), changed_len);
+	    modify_field (type, buffer.data (), value_as_long (fromval),
 			  value_bitpos (toval), value_bitsize (toval));
-	    dest_buffer = buffer;
+	    dest_buffer = buffer.data ();
+	  }
+	else if (value_bitpos (toval))
+	  {
+	    int bitpos = value_bitpos (toval);
+	    bool big_endian = type_byte_order (type) == BFD_ENDIAN_BIG;
+	    changed_addr = value_address (toval);
+	    changed_len = TYPE_LENGTH (type)
+			  + (bitpos + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT;
+	    buffer.resize (changed_len);
+	    read_memory (changed_addr, buffer.data (), changed_len);
+	    copy_bitwise (buffer.data (), bitpos,
+			  value_contents (fromval).data (), 0,
+			  TYPE_LENGTH (type) * HOST_CHAR_BIT, big_endian);
+	    dest_buffer = buffer.data();
 	  }
 	else
 	  {
@@ -1186,7 +1217,6 @@ value_assign (struct value *toval, struct value *fromval)
     case lval_register:
       {
 	struct frame_info *frame;
-	struct gdbarch *gdbarch;
 	int value_reg;
 
 	/* Figure out which frame this register value is in.  The value
@@ -1204,29 +1234,41 @@ value_assign (struct value *toval, struct value *fromval)
 	if (!frame)
 	  error (_("Value being assigned to is no longer active."));
 
-	gdbarch = get_frame_arch (frame);
+	gdbarch *arch = get_frame_arch (frame);
+	LONGEST bitpos = value_bitpos (toval);
+	LONGEST bitsize = value_bitsize (toval);
+	LONGEST offset = value_offset (toval);
 
-	if (value_bitsize (toval))
+	if (bitpos || bitsize)
 	  {
-	    struct value *parent = value_parent (toval);
-	    LONGEST offset = value_offset (parent) + value_offset (toval);
-	    size_t changed_len;
-	    gdb_byte buffer[sizeof (LONGEST)];
-	    int optim, unavail;
+	    int changed_len;
+	    bool big_endian = type_byte_order (type) == BFD_ENDIAN_BIG;
 
-	    changed_len = (value_bitpos (toval)
-			   + value_bitsize (toval)
-			   + HOST_CHAR_BIT - 1)
-			  / HOST_CHAR_BIT;
+	    if (bitsize)
+	      {
+		offset += value_offset (value_parent (toval));
 
-	    if (changed_len > sizeof (LONGEST))
-	      error (_("Can't handle bitfields which "
-		       "don't fit in a %d bit word."),
-		     (int) sizeof (LONGEST) * HOST_CHAR_BIT);
+		changed_len = (bitpos + bitsize + HOST_CHAR_BIT - 1)
+			      / HOST_CHAR_BIT;
+
+		if (changed_len > (int) sizeof (LONGEST))
+		  error (_("Can't handle bitfields which "
+			   "don't fit in a %d bit word."),
+			   (int) sizeof (LONGEST) * HOST_CHAR_BIT);
+	      }
+	    else
+	      {
+		changed_len = TYPE_LENGTH (type)
+			      + (bitpos + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT;
+
+		bitsize = TYPE_LENGTH (type) * HOST_CHAR_BIT;
+	      }
+
+	    gdb::byte_vector buffer (changed_len);
+	    int optim, unavail;
 
 	    if (!get_frame_register_bytes (frame, value_reg, offset,
-					   {buffer, changed_len},
-					   &optim, &unavail))
+					   buffer, &optim, &unavail))
 	      {
 		if (optim)
 		  throw_error (OPTIMIZED_OUT_ERROR,
@@ -1236,23 +1278,21 @@ value_assign (struct value *toval, struct value *fromval)
 			       _("value is not available"));
 	      }
 
-	    modify_field (type, buffer, value_as_long (fromval),
-			  value_bitpos (toval), value_bitsize (toval));
+	    copy_bitwise (buffer.data (), bitpos,
+			  value_contents (fromval).data (),
+			  0, bitsize, big_endian);
 
-	    put_frame_register_bytes (frame, value_reg, offset,
-				      {buffer, changed_len});
+	    put_frame_register_bytes (frame, value_reg, offset, buffer);
 	  }
 	else
 	  {
-	    if (gdbarch_convert_register_p (gdbarch, VALUE_REGNUM (toval),
-					    type))
+	    if (gdbarch_convert_register_p (arch, VALUE_REGNUM (toval), type))
 	      {
 		/* If TOVAL is a special machine register requiring
 		   conversion of program values to a special raw
 		   format.  */
-		gdbarch_value_to_register (gdbarch, frame,
-					   VALUE_REGNUM (toval), type,
-					   value_contents (fromval).data ());
+		gdbarch_value_to_register (arch, frame, VALUE_REGNUM (toval),
+					   type, value_contents (fromval).data ());
 	      }
 	    else
 	      {
@@ -1260,8 +1300,7 @@ value_assign (struct value *toval, struct value *fromval)
 		  = gdb::make_array_view (value_contents (fromval).data (),
 					  TYPE_LENGTH (type));
 		put_frame_register_bytes (frame, value_reg,
-					  value_offset (toval),
-					  contents);
+					  offset, contents);
 	      }
 	  }
 
@@ -1363,21 +1402,22 @@ value_assign (struct value *toval, struct value *fromval)
 struct value *
 value_repeat (struct value *arg1, int count)
 {
-  struct value *val;
-
   if (VALUE_LVAL (arg1) != lval_memory)
     error (_("Only values in memory can be extended with '@'."));
   if (count < 1)
     error (_("Invalid number %d of repetitions."), count);
 
-  val = allocate_repeat_value (value_enclosing_type (arg1), count);
+  value *val
+    = allocate_repeat_value (value_enclosing_type (arg1), count);
 
   VALUE_LVAL (val) = lval_memory;
   set_value_address (val, value_address (arg1));
+  set_value_bitpos (val, value_bitpos (arg1));
+  type *enclosing_type = value_enclosing_type (val);
 
-  read_value_memory (val, 0, value_stack (val), value_address (val),
-		     value_contents_all_raw (val).data (),
-		     type_length_units (value_enclosing_type (val)));
+  read_value_memory (val, value_bitpos (val), value_stack (val),
+		     value_address (val), value_contents_all_raw (val).data (),
+		     type_length_units (enclosing_type));
 
   return val;
 }
@@ -1726,7 +1766,7 @@ value_array (int lowbound, int highbound, struct value **elemvec)
     {
       val = allocate_value (arraytype);
       for (idx = 0; idx < nelem; idx++)
-	value_contents_copy (val, idx * typelength, elemvec[idx], 0,
+	value_contents_copy (val, idx * typelength, elemvec[idx], 0, 0,
 			     typelength);
       return val;
     }
@@ -1736,7 +1776,8 @@ value_array (int lowbound, int highbound, struct value **elemvec)
 
   val = allocate_value (arraytype);
   for (idx = 0; idx < nelem; idx++)
-    value_contents_copy (val, idx * typelength, elemvec[idx], 0, typelength);
+    value_contents_copy (val, idx * typelength, elemvec[idx], 0, 0,
+			 typelength);
   return val;
 }
 
@@ -4005,7 +4046,7 @@ value_slice (struct value *array, int lowbound, int length)
     else
       {
 	slice = allocate_value (slice_type);
-	value_contents_copy (slice, 0, array, offset,
+	value_contents_copy (slice, 0, array, offset, 0,
 			     type_length_units (slice_type));
       }
 
diff --git a/gdb/value.c b/gdb/value.c
index 7de858c7085..01af97141ef 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -1322,9 +1322,10 @@ value_ranges_copy_adjusted (struct value *dst, int dst_bit_offset,
 
 static void
 value_contents_copy_raw (struct value *dst, LONGEST dst_offset,
-			 struct value *src, LONGEST src_offset, LONGEST length)
+			 struct value *src, LONGEST src_offset,
+			 LONGEST src_bit_offset, LONGEST length)
 {
-  LONGEST src_bit_offset, dst_bit_offset, bit_length;
+  LONGEST src_total_bit_offset, dst_total_bit_offset, bit_length;
   struct gdbarch *arch = get_value_arch (src);
   int unit_size = gdbarch_addressable_memory_unit_size (arch);
 
@@ -1343,17 +1344,31 @@ value_contents_copy_raw (struct value *dst, LONGEST dst_offset,
 					     TARGET_CHAR_BIT * length));
 
   /* Copy the data.  */
-  memcpy (value_contents_all_raw (dst).data () + dst_offset * unit_size,
-	  value_contents_all_raw (src).data () + src_offset * unit_size,
-	  length * unit_size);
+  bit_length = length * unit_size * HOST_CHAR_BIT;
+
+  if (src_bit_offset)
+    {
+      bool big_endian = type_byte_order (value_type (dst)) == BFD_ENDIAN_BIG;
+
+      copy_bitwise (value_contents_all_raw (dst).data ()
+		      + dst_offset * unit_size, 0,
+		    value_contents_all_raw (src).data ()
+		      + src_offset * unit_size,
+		    src_bit_offset, bit_length, big_endian);
+    }
+  else
+    memcpy (value_contents_all_raw (dst).data () + dst_offset * unit_size,
+	    value_contents_all_raw (src).data () + src_offset * unit_size,
+	    length * unit_size);
 
   /* Copy the meta-data, adjusted.  */
-  src_bit_offset = src_offset * unit_size * HOST_CHAR_BIT;
-  dst_bit_offset = dst_offset * unit_size * HOST_CHAR_BIT;
-  bit_length = length * unit_size * HOST_CHAR_BIT;
+  src_total_bit_offset = src_offset * unit_size * HOST_CHAR_BIT
+			 + src_bit_offset;
+  dst_total_bit_offset = dst_offset * unit_size * HOST_CHAR_BIT;
+
 
-  value_ranges_copy_adjusted (dst, dst_bit_offset,
-			      src, src_bit_offset,
+  value_ranges_copy_adjusted (dst, dst_total_bit_offset,
+			      src, src_total_bit_offset,
 			      bit_length);
 }
 
@@ -1369,12 +1384,14 @@ value_contents_copy_raw (struct value *dst, LONGEST dst_offset,
 
 void
 value_contents_copy (struct value *dst, LONGEST dst_offset,
-		     struct value *src, LONGEST src_offset, LONGEST length)
+		     struct value *src, LONGEST src_offset,
+		     LONGEST src_bit_offset, LONGEST length)
 {
   if (src->lazy)
     value_fetch_lazy (src);
 
-  value_contents_copy_raw (dst, dst_offset, src, src_offset, length);
+  value_contents_copy_raw (dst, dst_offset, src, src_offset,
+			   src_bit_offset, length);
 }
 
 int
@@ -3089,7 +3106,7 @@ value_primitive_field (struct value *arg1, LONGEST offset,
       else
 	{
 	  v = allocate_value (value_enclosing_type (arg1));
-	  value_contents_copy_raw (v, 0, arg1, 0,
+	  value_contents_copy_raw (v, 0, arg1, 0, 0,
 				   TYPE_LENGTH (value_enclosing_type (arg1)));
 	}
       v->type = type;
@@ -3124,7 +3141,7 @@ value_primitive_field (struct value *arg1, LONGEST offset,
 	  v = allocate_value (type);
 	  value_contents_copy_raw (v, value_embedded_offset (v),
 				   arg1, value_embedded_offset (arg1) + offset,
-				   type_length_units (type));
+				   0, type_length_units (type));
 	}
       v->offset = (value_offset (arg1) + offset
 		   + value_embedded_offset (arg1));
@@ -3731,7 +3748,7 @@ value_from_component (struct value *whole, struct type *type, LONGEST offset)
       v = allocate_value (type);
       value_contents_copy (v, value_embedded_offset (v),
 			   whole, value_embedded_offset (whole) + offset,
-			   type_length_units (type));
+			   0, type_length_units (type));
     }
   v->offset = value_offset (whole) + offset + value_embedded_offset (whole);
   set_value_component_location (v, whole);
@@ -3913,9 +3930,9 @@ value_fetch_lazy_memory (struct value *val)
   struct type *type = check_typedef (value_enclosing_type (val));
 
   if (TYPE_LENGTH (type))
-      read_value_memory (val, 0, value_stack (val),
-			 addr, value_contents_all_raw (val).data (),
-			 type_length_units (type));
+    read_value_memory (val, value_bitpos (val), value_stack (val),
+		       addr, value_contents_all_raw (val).data (),
+		       type_length_units (type));
 }
 
 /* Helper for value_fetch_lazy when the value is in a register.  */
@@ -3928,10 +3945,6 @@ value_fetch_lazy_register (struct value *val)
   struct type *type = check_typedef (value_type (val));
   struct value *new_val = val, *mark = value_mark ();
 
-  /* Offsets are not supported here; lazy register values must
-     refer to the entire register.  */
-  gdb_assert (value_offset (val) == 0);
-
   while (VALUE_LVAL (new_val) == lval_register && value_lazy (new_val))
     {
       struct frame_id next_frame_id = VALUE_NEXT_FRAME_ID (new_val);
@@ -3974,6 +3987,11 @@ value_fetch_lazy_register (struct value *val)
 			_("infinite loop while fetching a register"));
     }
 
+  /* Check if NEW_VALUE is big enough to cover
+     the expected VAL type with an offset.  */
+  gdb_assert ((TYPE_LENGTH (type) + value_offset (val))
+	      <= TYPE_LENGTH (value_type (new_val)));
+
   /* If it's still lazy (for instance, a saved register on the
      stack), fetch it.  */
   if (value_lazy (new_val))
@@ -3982,9 +4000,9 @@ value_fetch_lazy_register (struct value *val)
   /* Copy the contents and the unavailability/optimized-out
      meta-data from NEW_VAL to VAL.  */
   set_value_lazy (val, 0);
-  value_contents_copy (val, value_embedded_offset (val),
-		       new_val, value_embedded_offset (new_val),
-		       type_length_units (type));
+  value_contents_copy (val, value_embedded_offset (val), new_val,
+		       value_embedded_offset (new_val) + value_offset (val),
+		       value_bitpos (val), type_length_units (type));
 
   if (frame_debug)
     {
diff --git a/gdb/value.h b/gdb/value.h
index 82b29c6292e..8468d3158d4 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -740,7 +740,7 @@ extern struct value *allocate_value (struct type *type);
 extern struct value *allocate_value_lazy (struct type *type);
 extern void value_contents_copy (struct value *dst, LONGEST dst_offset,
 				 struct value *src, LONGEST src_offset,
-				 LONGEST length);
+				 LONGEST src_bit_offset, LONGEST length);
 
 extern struct value *allocate_repeat_value (struct type *type, int count);
 
diff --git a/include/dwarf2.def b/include/dwarf2.def
index 1ae6e1df298..5e622695d60 100644
--- a/include/dwarf2.def
+++ b/include/dwarf2.def
@@ -704,6 +704,10 @@ DW_OP (DW_OP_PGI_omp_thread_num, 0xf8)
    to 0 except explicitly documented for one action.  Please refer AArch64 DWARF
    ABI documentation for details.  */
 DW_OP (DW_OP_AARCH64_operation, 0xea)
+/* LLVM extensions for heterogeneous targets */
+DW_OP_DUP (DW_OP_LLVM_offset, 0xe3)
+DW_OP_DUP (DW_OP_LLVM_offset_constu, 0xe4)
+DW_OP_DUP (DW_OP_LLVM_bit_offset, 0xe5)
 DW_END_OP
 
 DW_FIRST_ATE (DW_ATE_void, 0x0)
-- 
2.17.1


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

* [PATCH v4 25/28] Add support for DW_OP_LLVM_undefined operation
  2021-11-05 11:38 [PATCH v4 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (23 preceding siblings ...)
  2021-11-05 11:38 ` [PATCH v4 24/28] Add DWARF operations for byte and bit offset Zoran Zaric
@ 2021-11-05 11:38 ` Zoran Zaric
  2021-11-05 11:38 ` [PATCH v4 26/28] Add support for nested composite locations Zoran Zaric
                   ` (2 subsequent siblings)
  27 siblings, 0 replies; 38+ messages in thread
From: Zoran Zaric @ 2021-11-05 11:38 UTC (permalink / raw)
  To: gdb-patches

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

For the DW_OP_piece and DW_OP_bit_piece operations, in the DWARF 5
standard, it is stated that if the location description (of that piece)
is empty, then the piece is describing an undefined location
description.

The act of allowing any location description to be placed on a DWARF
stack means that now a new operations can be defined which could pop
more then one location description from a DWARF stack.

This means that the old rule is not really applicable any more and a
new operation that explicitly pushes an undefined location description
on the DWARF stack is needed.

This new rule however is fully backward compatibility as described
in the document found on:

https://llvm.org/docs/AMDGPUDwarfExtensionsForHeterogeneousDebugging.html

Under the new definitions for the DW_OP_piece and DW_OP_bit_piece
operations.

gdb/ChangeLog:

	* compile/compile-loc2c.c (compute_stack_depth_worker): Add
	support for new DW_OP_LLVM_undefined operations.
	* dwarf2/expr.c (dwarf_expr_context::execute_stack_op): Add
	support for new DW_OP_LLVM_undefined operations.
        * dwarf2/loc.c (dwarf2_get_symbol_read_needs): Add new
        DW_OP_LLVM_undefined operation support.

include/ChangeLog:

	* dwarf2.def (DW_OP): New DW_OP_LLVM_undefined operations
	enumeration.

gdb/testsuite/ChangeLog:

	* gdb.dwarf2/dw2-llvm-undefined.exp: New test.
---
 gdb/compile/compile-loc2c.c                   |   4 +
 gdb/dwarf2/expr.c                             |   4 +
 gdb/dwarf2/loc.c                              |   1 +
 .../gdb.dwarf2/dw2-llvm-undefined.exp         | 144 ++++++++++++++++++
 include/dwarf2.def                            |   1 +
 5 files changed, 154 insertions(+)
 create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-llvm-undefined.exp

diff --git a/gdb/compile/compile-loc2c.c b/gdb/compile/compile-loc2c.c
index 77eb5a8e19d..89f40e5513a 100644
--- a/gdb/compile/compile-loc2c.c
+++ b/gdb/compile/compile-loc2c.c
@@ -362,6 +362,10 @@ compute_stack_depth_worker (int start, int *need_tempvar,
 	  --stack_depth;
 	  break;
 
+	case DW_OP_LLVM_undefined:
+	  ++stack_depth;
+	  break;
+
 	case DW_OP_LLVM_offset_constu:
 	case DW_OP_nop:
 	  break;
diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index a0310fef7a4..540bc96a2d0 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -4051,6 +4051,10 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 	    break;
 	  }
 
+	case DW_OP_LLVM_undefined:
+	  push (make_unique<dwarf_undefined> (arch));
+	  break;
+
 	default:
 	  error (_("Unhandled dwarf expression opcode 0x%x"), op);
 	}
diff --git a/gdb/dwarf2/loc.c b/gdb/dwarf2/loc.c
index 7c0782404dd..d6e46f07717 100644
--- a/gdb/dwarf2/loc.c
+++ b/gdb/dwarf2/loc.c
@@ -1926,6 +1926,7 @@ dwarf2_get_symbol_read_needs (gdb::array_view<const gdb_byte> expr,
 	case DW_OP_push_object_address:
 	case DW_OP_LLVM_offset:
 	case DW_OP_LLVM_bit_offset:
+	case DW_OP_LLVM_undefined:
 	  break;
 
 	case DW_OP_form_tls_address:
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-llvm-undefined.exp b/gdb/testsuite/gdb.dwarf2/dw2-llvm-undefined.exp
new file mode 100644
index 00000000000..2bd678c1e0d
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-llvm-undefined.exp
@@ -0,0 +1,144 @@
+# Copyright 2017-2021 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test the new DW_OP_LLVM_undefined operation.
+#
+# The test uses a composite location description, where some pieces
+# of that location description are undefined location description.
+
+load_lib dwarf.exp
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+if {![dwarf2_support]} {
+    return 0
+}
+
+# Choose suitable integer registers for the test.
+
+set dwarf_regnum 0
+
+if { [is_aarch64_target] } {
+    set regname x0
+} elseif { [is_aarch32_target]
+	   || [istarget "s390*-*-*" ]
+	   || [istarget "powerpc*-*-*"]
+	   || [istarget "rs6000*-*-aix*"] } {
+    set regname r0
+} elseif { [is_x86_like_target] } {
+    set regname eax
+} elseif { [is_amd64_regs_target] } {
+    set regname rax
+} else {
+    verbose "Skipping ${gdb_test_file_name}."
+    return
+}
+
+standard_testfile var-access.c ${gdb_test_file_name}-dw.S
+
+# Make some DWARF for the test.
+
+set asm_file [standard_output_file $srcfile2]
+Dwarf::assemble $asm_file {
+    global dwarf_regnum regname srcdir subdir srcfile
+    set buf_src [gdb_target_symbol buf]
+
+    set main_result [function_range main ${srcdir}/${subdir}/${srcfile}]
+    set main_start [lindex $main_result 0]
+    set main_length [lindex $main_result 1]
+
+    cu {} {
+	DW_TAG_compile_unit {
+	    {DW_AT_name var-access.c}
+	    {DW_AT_comp_dir /tmp}
+	} {
+	    declare_labels int_type_label char_type_label array_type_label
+
+	    # define char type
+	    char_type_label: DW_TAG_base_type {
+		{DW_AT_name "char"}
+		{DW_AT_encoding @DW_ATE_signed}
+		{DW_AT_byte_size 1 DW_FORM_sdata}
+	    }
+
+	    int_type_label: DW_TAG_base_type {
+		{DW_AT_name "int"}
+		{DW_AT_encoding @DW_ATE_signed}
+		{DW_AT_byte_size 4 DW_FORM_sdata}
+	    }
+
+	    array_type_label: DW_TAG_array_type {
+		{DW_AT_type :$char_type_label}
+	    } {
+		DW_TAG_subrange_type {
+		    {DW_AT_type :$int_type_label}
+		    {DW_AT_upper_bound 5 DW_FORM_udata}
+		}
+	    }
+
+	    DW_TAG_subprogram {
+		{DW_AT_name main}
+		{DW_AT_low_pc $main_start addr}
+		{DW_AT_high_pc $main_length data8}
+	    } {
+
+		# Array spread in different pieces of which some are
+		# undefined (1st and sixth bytes) and some are in a
+		# REGNAME register.
+		DW_TAG_variable {
+		    {DW_AT_name var_array}
+		    {DW_AT_type :$array_type_label}
+		    {DW_AT_location {
+			DW_OP_LLVM_undefined
+			DW_OP_piece 0x1
+			DW_OP_regx $dwarf_regnum
+			DW_OP_piece 0x4
+			DW_OP_LLVM_undefined
+			DW_OP_piece 0x1
+		    } SPECIAL_expr}
+		}
+
+		DW_TAG_variable {
+		    {DW_AT_name var_int}
+		    {DW_AT_type :$int_type_label}
+		    {DW_AT_location {
+			DW_OP_LLVM_undefined
+		    } SPECIAL_expr}
+		}
+	    }
+	}
+    }
+}
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} \
+     [list $srcfile $asm_file] {nodebug}] } {
+    return -1
+}
+
+if ![runto_main] {
+    return -1
+}
+
+gdb_test_no_output "set var \$$regname = 0x04030201" "init reg"
+
+# Determine byte order.
+set endian [get_endianness]
+
+switch $endian {
+	little {set val "<optimized out>, 0x1, 0x2, 0x3, 0x4, <optimized out>"}
+	big {set val "<optimized out>, 0x4, 0x3, 0x2, 0x1, <optimized out>"}
+}
+
+gdb_test "print/x var_array" " = \\{${val}\\}" "var_array print"
+gdb_test "print/x var_int" " = <optimized out>" "var_int print"
diff --git a/include/dwarf2.def b/include/dwarf2.def
index 5e622695d60..1b626362ec4 100644
--- a/include/dwarf2.def
+++ b/include/dwarf2.def
@@ -708,6 +708,7 @@ DW_OP (DW_OP_AARCH64_operation, 0xea)
 DW_OP_DUP (DW_OP_LLVM_offset, 0xe3)
 DW_OP_DUP (DW_OP_LLVM_offset_constu, 0xe4)
 DW_OP_DUP (DW_OP_LLVM_bit_offset, 0xe5)
+DW_OP (DW_OP_LLVM_undefined, 0xe7)
 DW_END_OP
 
 DW_FIRST_ATE (DW_ATE_void, 0x0)
-- 
2.17.1


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

* [PATCH v4 26/28] Add support for nested composite locations
  2021-11-05 11:38 [PATCH v4 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (24 preceding siblings ...)
  2021-11-05 11:38 ` [PATCH v4 25/28] Add support for DW_OP_LLVM_undefined operation Zoran Zaric
@ 2021-11-05 11:38 ` 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
  27 siblings, 0 replies; 38+ messages in thread
From: Zoran Zaric @ 2021-11-05 11:38 UTC (permalink / raw)
  To: gdb-patches

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

After allowing a location description to be placed on a DWARF stack,
in an effort to achieve a full composability of the DWARF expression,
it is necessary to enable forming of a nested composite location
descriptions.

To be able do this, a new operation DW_OP_LLVM_piece_end needs to be
introduced, along with some additional rules on the way how the
composite location description is formed using the existing DW_OP_piece
and DW_OP_bit_piece operations. These new rules are fully compatible
with the composite forming rules from the DWARF 5 standard.

More details on the new operation and added rules can be found here:

https://llvm.org/docs/AMDGPUDwarfExtensionsForHeterogeneousDebugging.html

The dwarf_composite also needed to be modified to make a distinction
between completed composite locationd description and not completed
one.

This also mean that some DWARF expression operations can duplicate a
composite location description that is not completed and end up with
more then one different composite location description on the stack.
To be able to do this, classes that derive from a DWARF entry class
need to have a clone method.

gdb/ChangeLog:

        * compile/compile-loc2c.c (compute_stack_depth_worker): Add
        new DW_OP_LLVM_piece_end operation support.
        * dwarf2/expr.c (dwarf_composite::m_completed): New data
        member.
        (dwarf_entry::dwarf_entry): New copy constructor.
        (dwarf_location::dwarf_location): New copy constructor.
        (dwarf_value::dwarf_value): New copy constructor.
        (dwarf_undefined::dwarf_undefined): New copy constructor.
        (dwarf_memory::dwarf_memory): New copy constructor.
        (dwarf_register::dwarf_register): New copy constructor.
        (dwarf_implicit::dwarf_implicit): New method.
        (dwarf_implicit_pointer::dwarf_implicit_pointer): New copy
        constructor.
        (dwarf_composite::dwarf_composite): New copy constructor.
        (dwarf_entry::clone): New method.
        (dwarf_location::clone): New method.
        (dwarf_value::clone): New method.
        (dwarf_undefined::clone): New method.
        (dwarf_memory::clone): New method.
        (dwarf_register::clone): New method.
        (dwarf_implicit::clone): New method.
        (dwarf_implicit_pointer::clone): New method.
        (dwarf_composite::clone): New method.
        (dwarf_composite::is_completed): New method.
        (dwarf_composite::set_completed): New method.
        (dwarf_expr_context::add_piece): Use new composite forming
        rules.
        (dwarf_expr_context::execute_stack_op): Add new
        DW_OP_LLVM_piece_end operation support.
        * dwarf2/loc.c (dwarf2_get_symbol_read_needs): Add new
        DW_OP_LLVM_piece_end operation support.

include/ChangeLog:

        * dwarf2.def (DW_OP_DUP): Add new DW_OP_LLVM_piece_end
        enumeration.

gdb/testsuite/ChangeLog:

        * gdb.dwarf2/dw2-llvm-piece-end.exp: New test.
---
 gdb/compile/compile-loc2c.c                   |   1 +
 gdb/dwarf2/expr.c                             |  90 +++++++--
 gdb/dwarf2/loc.c                              |   1 +
 .../gdb.dwarf2/dw2-llvm-piece-end.exp         | 191 ++++++++++++++++++
 include/dwarf2.def                            |   1 +
 5 files changed, 270 insertions(+), 14 deletions(-)
 create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-llvm-piece-end.exp

diff --git a/gdb/compile/compile-loc2c.c b/gdb/compile/compile-loc2c.c
index 89f40e5513a..ba177726d4f 100644
--- a/gdb/compile/compile-loc2c.c
+++ b/gdb/compile/compile-loc2c.c
@@ -366,6 +366,7 @@ compute_stack_depth_worker (int start, int *need_tempvar,
 	  ++stack_depth;
 	  break;
 
+	case DW_OP_LLVM_piece_end:
 	case DW_OP_LLVM_offset_constu:
 	case DW_OP_nop:
 	  break;
diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index 540bc96a2d0..e767966ae0f 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -1576,9 +1576,20 @@ class dwarf_composite final : public dwarf_location
   void add_piece (std::unique_ptr<dwarf_location> location, ULONGEST bit_size)
   {
     gdb_assert (location != nullptr);
+    gdb_assert (!m_completed);
     m_pieces.emplace_back (std::move (location), bit_size);
   }
 
+  void set_completed (bool completed)
+  {
+    m_completed = completed;
+  };
+
+  bool is_completed () const
+  {
+    return m_completed;
+  };
+
   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;
@@ -1643,6 +1654,9 @@ class dwarf_composite final : public dwarf_location
 
   /* Vector of composite pieces.  */
   std::vector<piece> m_pieces;
+
+  /* True if location description is completed.  */
+  bool m_completed = false;
 };
 
 void
@@ -1655,6 +1669,9 @@ dwarf_composite::read (frame_info *frame, gdb_byte *buf,
   LONGEST total_bits_to_skip = bits_to_skip;
   unsigned int i;
 
+  if (!m_completed)
+    ill_formed_expression ();
+
   total_bits_to_skip += m_offset * HOST_CHAR_BIT + m_bit_suboffset;
 
   /* Skip pieces covered by the read offset.  */
@@ -1700,6 +1717,9 @@ dwarf_composite::write (frame_info *frame, const gdb_byte *buf,
   unsigned int pieces_num = m_pieces.size ();
   unsigned int i;
 
+  if (!m_completed)
+    ill_formed_expression ();
+
   total_bits_to_skip += m_offset * HOST_CHAR_BIT + m_bit_suboffset;
 
   /* Skip pieces covered by the write offset.  */
@@ -1952,14 +1972,16 @@ dwarf_composite::to_gdb_value (frame_info *frame, struct type *type,
     invalid_synthetic_pointer ();
 
   computed_closure *closure;
+  std::unique_ptr<dwarf_composite> composite_copy
+    = make_unique<dwarf_composite> (*this);
+  composite_copy->set_completed (true);
 
   /* 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);
+    closure = new computed_closure (std::move (composite_copy), frame);
   else
-    closure = new computed_closure (make_unique<dwarf_composite> (*this),
+    closure = new computed_closure (std::move (composite_copy),
 				    get_frame_id (frame));
 
   closure->incref ();
@@ -2472,13 +2494,35 @@ struct dwarf_expr_context
   /* Return true if the expression stack is empty.  */
   bool stack_empty_p () const;
 
-  /* Pop a top element of the stack and add as a composite piece
-     with an BIT_OFFSET offset and of a BIT_SIZE size.
+  /* Pop a top element of the stack and add as a composite piece.
+     The action is based on the context:
+
+      - If the stack is empty, then an incomplete composite location
+	description (comprised of one undefined location description),
+	is pushed on the stack.
+
+      - Otherwise, if the top stack entry is an incomplete composite
+	location description, then it is updated to append a new piece
+	comprised of one undefined location description.  The
+	incomplete composite location description is then left on the
+	stack.
+
+      - Otherwise, if the top stack entry is a location description or
+	can be converted to one, it is popped. Then:
+
+	 - If the top stack entry (after popping) is a location
+	   description comprised of one incomplete composite location
+	   description, then it is updated to append a new piece
+	   specified by the previously popped location description.
+	   The incomplete composite location description is then left
+	   on the stack.
+
+	 - Otherwise, a new location description comprised of one
+	   incomplete composite location description, with a new piece
+	   specified by the previously popped location description, is
+	   pushed on the stack.
 
-     If the following top element of the stack is a composite
-     location description, the piece will be added to it.  Otherwise
-     a new composite location description will be created, pushed on
-     the stack and the piece will be added to that composite.  */
+      - Otherwise, the DWARF expression is ill-formed  */
   void add_piece (ULONGEST bit_size, ULONGEST bit_offset);
 
   /* The engine for the expression evaluator.  Using the context in this
@@ -2801,10 +2845,11 @@ dwarf_expr_context::add_piece (ULONGEST bit_size, ULONGEST bit_offset)
       dwarf_composite *top_entry_as_composite
 	= dynamic_cast <dwarf_composite *> (&top_entry);
 
-      if (top_entry_as_composite == nullptr)
-	piece = to_location (pop (), arch);
-      else
+      if (top_entry_as_composite != nullptr
+	  && !top_entry_as_composite->is_completed ())
 	piece = make_unique<dwarf_undefined> (arch);
+      else
+	piece = to_location (pop (), arch);
     }
 
   piece->add_bit_offset (bit_offset);
@@ -2824,9 +2869,13 @@ dwarf_expr_context::add_piece (ULONGEST bit_size, ULONGEST bit_offset)
   else
     {
       dwarf_entry &top_entry = fetch (0);
-      composite = dynamic_cast <dwarf_composite *> (&top_entry);
+      dwarf_composite *top_entry_as_composite
+	= dynamic_cast <dwarf_composite *> (&top_entry);
 
-      if (composite == nullptr)
+      if (top_entry_as_composite != nullptr
+	  && !top_entry_as_composite->is_completed ())
+	composite = top_entry_as_composite;
+      else
 	{
 	  std::unique_ptr<dwarf_composite> new_composite
 	    = make_unique<dwarf_composite> (arch, this->m_per_cu);
@@ -4055,6 +4104,19 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 	  push (make_unique<dwarf_undefined> (arch));
 	  break;
 
+	case DW_OP_LLVM_piece_end:
+	  {
+	    dwarf_entry &entry = fetch (0);
+	    dwarf_composite *composite
+	      = dynamic_cast<dwarf_composite *> (&entry);
+
+	    if (composite == nullptr || composite->is_completed ())
+	      ill_formed_expression ();
+
+	    composite->set_completed (true);
+	    break;
+	  }
+
 	default:
 	  error (_("Unhandled dwarf expression opcode 0x%x"), op);
 	}
diff --git a/gdb/dwarf2/loc.c b/gdb/dwarf2/loc.c
index d6e46f07717..8bda8171ac1 100644
--- a/gdb/dwarf2/loc.c
+++ b/gdb/dwarf2/loc.c
@@ -1927,6 +1927,7 @@ dwarf2_get_symbol_read_needs (gdb::array_view<const gdb_byte> expr,
 	case DW_OP_LLVM_offset:
 	case DW_OP_LLVM_bit_offset:
 	case DW_OP_LLVM_undefined:
+	case DW_OP_LLVM_piece_end:
 	  break;
 
 	case DW_OP_form_tls_address:
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-llvm-piece-end.exp b/gdb/testsuite/gdb.dwarf2/dw2-llvm-piece-end.exp
new file mode 100644
index 00000000000..573bec2a790
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-llvm-piece-end.exp
@@ -0,0 +1,191 @@
+# Copyright (C) 2017-2021 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test the nested composition location description by using the new
+# DW_OP_LLVM_piece_end operation.
+#
+# The test uses three nested levels of composite location descriptions
+# to define a location of an array.
+
+load_lib dwarf.exp
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+if {![dwarf2_support]} {
+    return 0
+}
+
+# Choose suitable integer registers for the test.
+
+set dwarf_regnum 0
+
+if { [is_aarch64_target] } {
+    set regname x0
+} elseif { [is_aarch32_target]
+	   || [istarget "s390*-*-*" ]
+	   || [istarget "powerpc*-*-*"]
+	   || [istarget "rs6000*-*-aix*"] } {
+    set regname r0
+} elseif { [is_x86_like_target] } {
+    set regname eax
+} elseif { [is_amd64_regs_target] } {
+    set regname rax
+} else {
+    verbose "Skipping ${gdb_test_file_name}."
+    return
+}
+
+standard_testfile var-access.c ${gdb_test_file_name}-dw.S
+
+# Make some DWARF for the test.
+
+set asm_file [standard_output_file $srcfile2]
+Dwarf::assemble $asm_file {
+    global dwarf_regnum regname srcdir subdir srcfile
+    set buf_src [gdb_target_symbol buf]
+
+    set main_result [function_range main ${srcdir}/${subdir}/${srcfile}]
+    set main_start [lindex $main_result 0]
+    set main_length [lindex $main_result 1]
+
+    cu {} {
+	DW_TAG_compile_unit {
+	    {DW_AT_name var-access.c}
+	    {DW_AT_comp_dir /tmp}
+	} {
+	    declare_labels array_type_label int_type_label char_type_label
+
+	    # define char type
+	    char_type_label: DW_TAG_base_type {
+		{DW_AT_name "char"}
+		{DW_AT_encoding @DW_ATE_signed}
+		{DW_AT_byte_size 1 DW_FORM_sdata}
+	    }
+
+	    int_type_label: DW_TAG_base_type {
+		{DW_AT_name "int"}
+		{DW_AT_encoding @DW_ATE_signed}
+		{DW_AT_byte_size 4 DW_FORM_sdata}
+	    }
+
+	    array_type_label: DW_TAG_array_type {
+		{DW_AT_type :$char_type_label}
+	    } {
+		DW_TAG_subrange_type {
+		    {DW_AT_type :$int_type_label}
+		    {DW_AT_upper_bound 7 DW_FORM_udata}
+		}
+	    }
+
+	    DW_TAG_subprogram {
+		{DW_AT_name main}
+		{DW_AT_low_pc $main_start addr}
+		{DW_AT_high_pc $main_length data8}
+	    } {
+		# Array spread in different pieces, of which some are
+		# undefined (1st and sixth bytes) and some are either
+		# in buf variable or REGNAME register.
+		#
+		# Location consists of three nested composite levels:
+		# - Third level consists of a composite location
+		# descriptions which hold a single simple location
+		# description each.
+		# - Second level consist of two more composite location
+		# descriptions that hold two of the third level
+		# composite location descriptions.
+		# - First level holds two of the second level composite
+		# location descriptions.
+
+		DW_TAG_variable {
+		    {DW_AT_name var_array}
+		    {DW_AT_type :$array_type_label}
+		    {DW_AT_location {
+			# First level composite start
+			# Second level first composite start
+			# Third level first composite start
+			DW_OP_addr $buf_src
+			DW_OP_piece 0x2
+			DW_OP_LLVM_piece_end
+			# Third level first composite end
+
+			# Third level second composite start
+			DW_OP_LLVM_undefined
+			DW_OP_piece 0x1
+			DW_OP_LLVM_piece_end
+			# Third level second composite end
+
+			DW_OP_piece 0x1
+			DW_OP_swap
+			DW_OP_piece 0x2
+			DW_OP_LLVM_piece_end
+			# Second level first composite end
+
+			# Second level second composite start
+			# Third level third composite start
+			DW_OP_regx $dwarf_regnum
+			DW_OP_piece 0x4
+			DW_OP_LLVM_piece_end
+			# Third level third composite end
+
+			# Third level fourth composite start
+			DW_OP_LLVM_undefined
+			DW_OP_piece 0x1
+			DW_OP_LLVM_piece_end
+			# Third level fourth composite end
+
+			DW_OP_piece 0x1
+			DW_OP_swap
+			DW_OP_piece 0x4
+			DW_OP_LLVM_piece_end
+			# Second level second composite end
+
+			DW_OP_piece 0x5
+			DW_OP_swap
+			DW_OP_piece 0x3
+			DW_OP_LLVM_piece_end
+			# First level composite end
+
+		    } SPECIAL_expr}
+		}
+	    }
+	}
+    }
+}
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} \
+     [list $srcfile $asm_file] {nodebug}] } {
+    return -1
+}
+
+if ![runto_main] {
+    return -1
+}
+
+gdb_test_no_output "set var \$$regname = 0x4030201" "init reg"
+
+# Determine byte order.
+set endian [get_endianness]
+set optimized "<optimized out>"
+
+switch $endian {
+    little {
+	set val "$optimized, 0x1, 0x2, 0x3, 0x4, $optimized, 0x0, 0x1"
+    }
+    big {
+	set val "$optimized, 0x4, 0x3, 0x2, 0x1, $optimized, 0x0, 0x1"
+    }
+}
+
+gdb_test "print/x var_array" " = \\{${val}\\}" "var_array print"
+
diff --git a/include/dwarf2.def b/include/dwarf2.def
index 1b626362ec4..c6669221041 100644
--- a/include/dwarf2.def
+++ b/include/dwarf2.def
@@ -709,6 +709,7 @@ DW_OP_DUP (DW_OP_LLVM_offset, 0xe3)
 DW_OP_DUP (DW_OP_LLVM_offset_constu, 0xe4)
 DW_OP_DUP (DW_OP_LLVM_bit_offset, 0xe5)
 DW_OP (DW_OP_LLVM_undefined, 0xe7)
+DW_OP_DUP (DW_OP_LLVM_piece_end, 0xea)
 DW_END_OP
 
 DW_FIRST_ATE (DW_ATE_void, 0x0)
-- 
2.17.1


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

* [PATCH v4 27/28] Add DW_OP_LLVM_extend DWARF operation
  2021-11-05 11:38 [PATCH v4 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (25 preceding siblings ...)
  2021-11-05 11:38 ` [PATCH v4 26/28] Add support for nested composite locations Zoran Zaric
@ 2021-11-05 11:38 ` Zoran Zaric
  2021-11-05 11:38 ` [PATCH v4 28/28] Add DW_OP_LLVM_select_bit_piece " Zoran Zaric
  27 siblings, 0 replies; 38+ messages in thread
From: Zoran Zaric @ 2021-11-05 11:38 UTC (permalink / raw)
  To: gdb-patches

Previous changes allow a new set of more complex DWARF expression
operations to be added which are very usefull for SIMD/SIMT like
architectures. First of which is the DW_OP_LLVM_extend operation
that pops one stack element (which must be a location description)
and treat it as a number of pieces of a new composite location
description.

This means that a resulting composite location contains a given
number of pieces of a given bit size, where all the pieces are
described by the same location description found on top of the stack.

gdb/ChangeLog:

        * compile/compile-loc2c.c (compute_stack_depth_worker): Add
        new DW_OP_LLVM_extend operation support.
        * dwarf2/expr.c (dwarf_expr_context::create_extend_composite):
        New method that creates the extend composite.
        (dwarf_expr_context::execute_stack_op): Add new
        DW_OP_LLVM_extend operation support.
        * dwarf2/loc.c (dwarf2_get_symbol_read_needs): Add new
        DW_OP_LLVM_extend operation support.
        (disassemble_dwarf_expression): Add new DW_OP_LLVM_extend
        operation support.

include/ChangeLog:

        * dwarf2.def: Add new DW_OP_LLVM_extend enumeration.

gdb/testsuite/ChangeLog:

        * gdb.dwarf2/dw2-llvm-extend.exp: New test.
        * lib/dwarf.exp: Add new DW_OP_LLVM_extend operation support.
---
 gdb/compile/compile-loc2c.c                  |   1 +
 gdb/dwarf2/expr.c                            |  44 ++++++
 gdb/dwarf2/loc.c                             |  12 ++
 gdb/testsuite/gdb.dwarf2/dw2-llvm-extend.exp | 147 +++++++++++++++++++
 gdb/testsuite/lib/dwarf.exp                  |   5 +
 include/dwarf2.def                           |   1 +
 6 files changed, 210 insertions(+)
 create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-llvm-extend.exp

diff --git a/gdb/compile/compile-loc2c.c b/gdb/compile/compile-loc2c.c
index ba177726d4f..26a4def312c 100644
--- a/gdb/compile/compile-loc2c.c
+++ b/gdb/compile/compile-loc2c.c
@@ -366,6 +366,7 @@ compute_stack_depth_worker (int start, int *need_tempvar,
 	  ++stack_depth;
 	  break;
 
+	case DW_OP_LLVM_extend:
 	case DW_OP_LLVM_piece_end:
 	case DW_OP_LLVM_offset_constu:
 	case DW_OP_nop:
diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index e767966ae0f..f8c23a7842d 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -2525,6 +2525,15 @@ struct dwarf_expr_context
       - Otherwise, the DWARF expression is ill-formed  */
   void add_piece (ULONGEST bit_size, ULONGEST bit_offset);
 
+  /* It pops one stack entry that must be a location description and is
+     treated as a piece location description.
+
+     A complete composite location storage is created with PIECES_COUNT
+     identical pieces and pushed on the DWARF stack.  Each pieces has a
+     bit size of PIECE_BIT_SIZE.  */
+  void create_extend_composite (ULONGEST piece_bit_size,
+				ULONGEST pieces_count);
+
   /* The engine for the expression evaluator.  Using the context in this
      object, evaluate the expression between OP_PTR and OP_END.  */
   void execute_stack_op (const gdb_byte *op_ptr, const gdb_byte *op_end);
@@ -2887,6 +2896,30 @@ dwarf_expr_context::add_piece (ULONGEST bit_size, ULONGEST bit_offset)
   composite->add_piece (std::move (piece), bit_size);
 }
 
+void
+dwarf_expr_context::create_extend_composite (ULONGEST piece_bit_size,
+					     ULONGEST pieces_count)
+{
+  gdbarch *arch = this->m_per_objfile->objfile->arch ();
+
+  if (stack_empty_p () || piece_bit_size == 0 || pieces_count == 0)
+    ill_formed_expression ();
+
+  dwarf_location_up location = to_location (pop (), arch);
+
+  std::unique_ptr<dwarf_composite> composite
+    = make_unique<dwarf_composite> (arch, this->m_per_cu);
+
+  for (ULONGEST i = 0; i < pieces_count; i++)
+    {
+      dwarf_location_up piece = location->clone_location ();
+      composite->add_piece (std::move (piece), piece_bit_size);
+    }
+
+  composite->set_completed (true);
+  push (std::move (composite));
+}
+
 void
 dwarf_expr_context::eval (const gdb_byte *addr, size_t len)
 {
@@ -4117,6 +4150,17 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 	    break;
 	  }
 
+	case DW_OP_LLVM_extend:
+	  {
+	    uint64_t piece_bit_size, pieces_count;
+
+	    /* Record the piece.  */
+	    op_ptr = safe_read_uleb128 (op_ptr, op_end, &piece_bit_size);
+	    op_ptr = safe_read_uleb128 (op_ptr, op_end, &pieces_count);
+	    create_extend_composite (piece_bit_size, pieces_count);
+	    break;
+	  }
+
 	default:
 	  error (_("Unhandled dwarf expression opcode 0x%x"), op);
 	}
diff --git a/gdb/dwarf2/loc.c b/gdb/dwarf2/loc.c
index 8bda8171ac1..d8bcd542776 100644
--- a/gdb/dwarf2/loc.c
+++ b/gdb/dwarf2/loc.c
@@ -1954,6 +1954,7 @@ dwarf2_get_symbol_read_needs (gdb::array_view<const gdb_byte> expr,
 	  break;
 
 	case DW_OP_bit_piece:
+	case DW_OP_LLVM_extend:
 	  op_ptr = safe_skip_leb128 (op_ptr, expr_end);
 	  op_ptr = safe_skip_leb128 (op_ptr, expr_end);
 	  break;
@@ -3667,6 +3668,17 @@ disassemble_dwarf_expression (struct ui_file *stream,
 	  data = safe_read_uleb128 (data, end, &ul);
 	  fprintf_filtered (stream, " %s", pulongest (ul));
 	  break;
+
+	case DW_OP_LLVM_extend:
+	  {
+	    uint64_t count;
+
+	    data = safe_read_uleb128 (data, end, &ul);
+	    data = safe_read_uleb128 (data, end, &count);
+	    fprintf_filtered (stream, " piece size %s (bits) pieces count %s",
+	                      pulongest (ul), pulongest (count));
+	  }
+	  break;
 	}
 
       fprintf_filtered (stream, "\n");
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-llvm-extend.exp b/gdb/testsuite/gdb.dwarf2/dw2-llvm-extend.exp
new file mode 100644
index 00000000000..f682c40acd9
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-llvm-extend.exp
@@ -0,0 +1,147 @@
+# Copyright (C) 2017-2021 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test the new DW_OP_LLVM_extend operation.
+#
+# The test uses a composite location description, where all the pieces
+# are allocated in the same register by using the new operation.
+
+load_lib dwarf.exp
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+if {![dwarf2_support]} {
+    return 0
+}
+
+# Choose suitable integer registers for the test.
+
+set dwarf_regnum 0
+
+if { [is_aarch64_target] } {
+    set regname x0
+} elseif { [is_aarch32_target]
+	   || [istarget "s390*-*-*" ]
+	   || [istarget "powerpc*-*-*"]
+	   || [istarget "rs6000*-*-aix*"] } {
+    set regname r0
+} elseif { [is_x86_like_target] } {
+    set regname eax
+} elseif { [is_amd64_regs_target] } {
+    set regname rax
+} else {
+    verbose "Skipping ${gdb_test_file_name}."
+    return
+}
+
+standard_testfile var-access.c ${gdb_test_file_name}-dw.S
+
+# Make some DWARF for the test.
+
+set asm_file [standard_output_file $srcfile2]
+Dwarf::assemble $asm_file {
+    global dwarf_regnum regname srcdir subdir srcfile
+    set buf_src [gdb_target_symbol buf]
+
+    set main_result [function_range main ${srcdir}/${subdir}/${srcfile}]
+    set main_start [lindex $main_result 0]
+    set main_length [lindex $main_result 1]
+
+    cu {} {
+	DW_TAG_compile_unit {
+	    {DW_AT_name var-access.c}
+	    {DW_AT_comp_dir /tmp}
+	} {
+	    declare_labels int_type_label char_type_label array_type_label
+
+	    # define char type
+	    char_type_label: DW_TAG_base_type {
+		{DW_AT_name "char"}
+		{DW_AT_encoding @DW_ATE_signed}
+		{DW_AT_byte_size 1 DW_FORM_sdata}
+	    }
+
+	    int_type_label: DW_TAG_base_type {
+		{DW_AT_name "int"}
+		{DW_AT_encoding @DW_ATE_signed}
+		{DW_AT_byte_size 4 DW_FORM_sdata}
+	    }
+
+	    array_type_label: DW_TAG_array_type {
+		{DW_AT_type :$char_type_label}
+	    } {
+		DW_TAG_subrange_type {
+		    {DW_AT_type :$int_type_label}
+		    {DW_AT_upper_bound 7 DW_FORM_udata}
+		}
+	    }
+
+	    DW_TAG_subprogram {
+		{DW_AT_name main}
+		{DW_AT_low_pc $main_start addr}
+		{DW_AT_high_pc $main_length data8}
+	    } {
+
+		# All array elements are in first byte of REGNAME register.
+		DW_TAG_variable {
+		    {DW_AT_name var_array_1}
+		    {DW_AT_type :$array_type_label}
+		    {DW_AT_location {
+			DW_OP_regx $dwarf_regnum
+			DW_OP_LLVM_extend 8 8
+		    } SPECIAL_expr}
+		}
+
+		# All array elements are in fourth byte of REGNAME register.
+		DW_TAG_variable {
+		    {DW_AT_name var_array_2}
+		    {DW_AT_type :$array_type_label}
+		    {DW_AT_location {
+			DW_OP_regx $dwarf_regnum
+			DW_OP_LLVM_offset_constu 3
+			DW_OP_LLVM_extend 8 8
+		    } SPECIAL_expr}
+		}
+	    }
+	}
+    }
+}
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} \
+     [list $srcfile $asm_file] {nodebug}] } {
+    return -1
+}
+
+if ![runto_main] {
+    return -1
+}
+
+gdb_test_no_output "set var \$$regname = 0x04030201" "init reg"
+
+# Determine byte order.
+set endian [get_endianness]
+
+switch $endian {
+	little {set val "0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1"}
+	big {set val "0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4"}
+}
+
+gdb_test "print/x var_array_1" " = \\{${val}\\}" "var_array_1 print"
+
+switch $endian {
+	little {set val "0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4"}
+	big {set val "0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1"}
+}
+
+gdb_test "print/x var_array_2" " = \\{${val}\\}" "var_array_2 print"
diff --git a/gdb/testsuite/lib/dwarf.exp b/gdb/testsuite/lib/dwarf.exp
index 48a10aedf26..d2f3445c926 100644
--- a/gdb/testsuite/lib/dwarf.exp
+++ b/gdb/testsuite/lib/dwarf.exp
@@ -1225,6 +1225,11 @@ namespace eval Dwarf {
 		    _op .uleb128 [lindex $line 1]
 		}
 
+		DW_OP_LLVM_extend {
+		    _op .uleb128 [lindex $line 1]
+		    _op .uleb128 [lindex $line 2]
+		}
+
 		default {
 		    if {[llength $line] > 1} {
 			error "Unimplemented: operands in location for $opcode"
diff --git a/include/dwarf2.def b/include/dwarf2.def
index c6669221041..3d1d831d0fb 100644
--- a/include/dwarf2.def
+++ b/include/dwarf2.def
@@ -710,6 +710,7 @@ DW_OP_DUP (DW_OP_LLVM_offset_constu, 0xe4)
 DW_OP_DUP (DW_OP_LLVM_bit_offset, 0xe5)
 DW_OP (DW_OP_LLVM_undefined, 0xe7)
 DW_OP_DUP (DW_OP_LLVM_piece_end, 0xea)
+DW_OP (DW_OP_LLVM_extend, 0xeb)
 DW_END_OP
 
 DW_FIRST_ATE (DW_ATE_void, 0x0)
-- 
2.17.1


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

* [PATCH v4 28/28] Add DW_OP_LLVM_select_bit_piece DWARF operation
  2021-11-05 11:38 [PATCH v4 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (26 preceding siblings ...)
  2021-11-05 11:38 ` [PATCH v4 27/28] Add DW_OP_LLVM_extend DWARF operation Zoran Zaric
@ 2021-11-05 11:38 ` Zoran Zaric
  27 siblings, 0 replies; 38+ messages in thread
From: Zoran Zaric @ 2021-11-05 11:38 UTC (permalink / raw)
  To: gdb-patches

Second more complex DWARF expression operation, that is usefull for
SIMD/SIMT like architectures is DW_OP_LLVM_select_bit_piece. This
operation pops three stack entries, where the first must be an integral
type value that represents a bit mask, the second must be a location
description that represents the one-location description and the third
must be a location description that represents the zero-location
description.

Resulting composite location description contains a given number of
pieces of a given bit size, created with parts from either of the two
location description, based on the bit mask.

gdb/ChangeLog:

        * compile/compile-loc2c.c (compute_stack_depth_worker): Add
        new DW_OP_LLVM_select_bit_piece operation support.
        * dwarf2/expr.c (dwarf_expr_context::create_select_composite):
        New method that creates the select bit piece composite.
        (dwarf_location::slice): New method.
        (dwarf_composite::slice): New method.
        (dwarf_expr_context::execute_stack_op): Add new
        DW_OP_LLVM_select_bit_piece operation support.
        * dwarf2/loc.c (dwarf2_get_symbol_read_needs): Add new
        DW_OP_LLVM_select_bit_piece operation support.
        (disassemble_dwarf_expression): Add new
        DW_OP_LLVM_select_bit_piece operation support.

include/ChangeLog:

        * dwarf2.def: Add new DW_OP_LLVM_select_bit_piece enumeration.

gdb/testsuite/ChangeLog:

        * gdb.dwarf2/dw2-llvm-select-bit-piece.exp: New test.
        * lib/dwarf.exp: Add new DW_OP_LLVM_select_bit_piece operation
        support.
---
 gdb/compile/compile-loc2c.c                   |   4 +
 gdb/dwarf2/expr.c                             | 160 ++++++++++++++++++
 gdb/dwarf2/loc.c                              |  12 ++
 .../gdb.dwarf2/dw2-llvm-select-bit-piece.exp  | 138 +++++++++++++++
 gdb/testsuite/lib/dwarf.exp                   |   5 +
 include/dwarf2.def                            |   1 +
 6 files changed, 320 insertions(+)
 create mode 100644 gdb/testsuite/gdb.dwarf2/dw2-llvm-select-bit-piece.exp

diff --git a/gdb/compile/compile-loc2c.c b/gdb/compile/compile-loc2c.c
index 26a4def312c..83863276b4c 100644
--- a/gdb/compile/compile-loc2c.c
+++ b/gdb/compile/compile-loc2c.c
@@ -366,6 +366,10 @@ compute_stack_depth_worker (int start, int *need_tempvar,
 	  ++stack_depth;
 	  break;
 
+	case DW_OP_LLVM_select_bit_piece:
+	  stack_depth -= 2;
+	  break;
+
 	case DW_OP_LLVM_extend:
 	case DW_OP_LLVM_piece_end:
 	case DW_OP_LLVM_offset_constu:
diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index f8c23a7842d..3ae1a6289dd 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -461,6 +461,15 @@ class dwarf_location : public dwarf_entry
     ill_formed_expression ();
   }
 
+  /* Make a slice of a location description with an added bit offset
+     BIT_OFFSET and BIT_SIZE size in bits.
+
+     In the case of a composite location description, function returns
+     a minimum subset of that location description that starts on a
+     given offset of a given size.  */
+  virtual std::unique_ptr<dwarf_location> slice (LONGEST bit_offset,
+						 LONGEST bit_size) const;
+
   /* Read contents from the described location.
 
      The read operation is performed in the context of a FRAME.
@@ -616,6 +625,17 @@ class dwarf_location : public dwarf_entry
 
 using dwarf_location_up = std::unique_ptr<dwarf_location>;
 
+/* This is a default implementation used for
+   non-composite location descriptions.  */
+
+std::unique_ptr<dwarf_location>
+dwarf_location::slice (LONGEST bit_offset, LONGEST bit_size) const
+{
+  dwarf_location_up location_slice = this->clone_location ();
+  location_slice->add_bit_offset (bit_offset);
+  return location_slice;
+}
+
 void
 dwarf_location::read_from_gdb_value (frame_info *frame, struct value *value,
 				     int value_bit_offset,
@@ -1573,6 +1593,9 @@ class dwarf_composite final : public dwarf_location
     return make_unique<dwarf_composite> (*this);
   }
 
+  std::unique_ptr<dwarf_location> slice (LONGEST bit_offset,
+					 LONGEST bit_size) const override;
+
   void add_piece (std::unique_ptr<dwarf_location> location, ULONGEST bit_size)
   {
     gdb_assert (location != nullptr);
@@ -1659,6 +1682,64 @@ class dwarf_composite final : public dwarf_location
   bool m_completed = false;
 };
 
+std::unique_ptr<dwarf_location>
+dwarf_composite::slice (LONGEST bit_offset, LONGEST bit_size) const
+{
+  /* Size 0 is never expected at this point.  */
+  gdb_assert (bit_size != 0);
+
+  unsigned int pieces_num = m_pieces.size ();
+  LONGEST total_bit_size = bit_size;
+  LONGEST total_bits_to_skip = m_offset * HOST_CHAR_BIT
+			       + m_bit_suboffset + bit_offset;
+  std::vector<piece> piece_slices;
+  unsigned int i;
+
+  for (i = 0; i < pieces_num; i++)
+    {
+      LONGEST piece_bit_size = m_pieces[i].size;
+
+      if (total_bits_to_skip < piece_bit_size)
+	break;
+
+      total_bits_to_skip -= piece_bit_size;
+    }
+
+  for (; i < pieces_num; i++)
+    {
+      if (total_bit_size == 0)
+	break;
+
+      gdb_assert (total_bit_size > 0);
+      LONGEST slice_bit_size = m_pieces[i].size - total_bits_to_skip;
+
+      if (total_bit_size < slice_bit_size)
+	slice_bit_size = total_bit_size;
+
+      std::unique_ptr<dwarf_location> slice
+	= m_pieces[i].location->slice (total_bits_to_skip, slice_bit_size);
+      piece_slices.emplace_back (std::move (slice), slice_bit_size);
+
+      total_bit_size -= slice_bit_size;
+      total_bits_to_skip = 0;
+    }
+
+  unsigned int slices_num = piece_slices.size ();
+
+  /* Only one piece found, so there is no reason to
+      make a composite location description.  */
+  if (slices_num == 1)
+    return std::move (piece_slices[0].location);
+
+  std::unique_ptr<dwarf_composite> composite_slice
+    = make_unique<dwarf_composite> (m_arch, m_per_cu);
+
+  for (piece &piece : piece_slices)
+    composite_slice->add_piece (std::move (piece.location), piece.size);
+
+  return composite_slice;
+}
+
 void
 dwarf_composite::read (frame_info *frame, gdb_byte *buf,
 		       int buf_bit_offset, size_t bit_size,
@@ -2534,6 +2615,20 @@ struct dwarf_expr_context
   void create_extend_composite (ULONGEST piece_bit_size,
 				ULONGEST pieces_count);
 
+  /* It pops three stack entries.  The first must be an integral type
+     value that represents a bit mask.  The second must be a location
+     description that represents the one-location description.  The
+     third must be a location description that represents the
+     zero-location description.
+
+     A complete composite location description created with parts from
+     either of the two location description, based on the bit mask,
+     is pushed on top of the DWARF stack.  PIECE_BIT_SIZE represent
+     a size in bits of each piece and PIECES_COUNT represents a number
+     of pieces required.  */
+  void create_select_composite (ULONGEST piece_bit_size,
+				ULONGEST pieces_count);
+
   /* The engine for the expression evaluator.  Using the context in this
      object, evaluate the expression between OP_PTR and OP_END.  */
   void execute_stack_op (const gdb_byte *op_ptr, const gdb_byte *op_end);
@@ -2920,6 +3015,60 @@ dwarf_expr_context::create_extend_composite (ULONGEST piece_bit_size,
   push (std::move (composite));
 }
 
+void
+dwarf_expr_context::create_select_composite (ULONGEST piece_bit_size,
+					     ULONGEST pieces_count)
+{
+  gdb::byte_vector mask_buf;
+  gdbarch *arch = this->m_per_objfile->objfile->arch ();
+
+  if (stack_empty_p () || piece_bit_size == 0 || pieces_count == 0)
+    ill_formed_expression ();
+
+  dwarf_value_up mask = to_value (pop (), address_type ());
+
+  type *mask_type = mask->type ();
+  ULONGEST mask_size = TYPE_LENGTH (mask_type);
+  dwarf_require_integral (mask_type);
+
+  if (mask_size * HOST_CHAR_BIT < pieces_count)
+    ill_formed_expression ();
+
+  mask_buf.resize (mask_size);
+
+  copy_bitwise (mask_buf.data (), 0, mask->contents ().data (),
+		0, mask_size * HOST_CHAR_BIT,
+		type_byte_order (mask_type) == BFD_ENDIAN_BIG);
+
+  if (stack_empty_p ())
+    ill_formed_expression ();
+
+  dwarf_location_up one = to_location (pop (), arch);
+
+  if (stack_empty_p ())
+    ill_formed_expression ();
+
+  dwarf_location_up zero = to_location (pop (), arch);
+
+  std::unique_ptr<dwarf_composite> composite
+    = make_unique<dwarf_composite> (arch, this->m_per_cu);
+
+  for (ULONGEST i = 0; i < pieces_count; i++)
+    {
+      std::unique_ptr<dwarf_location> slice;
+
+      if ((mask_buf.data ()[i / HOST_CHAR_BIT] >> (i % HOST_CHAR_BIT)) & 1)
+	slice = one->slice (i * piece_bit_size, piece_bit_size);
+      else
+	slice = zero->slice (i * piece_bit_size, piece_bit_size);
+
+      composite->add_piece (std::move (slice), piece_bit_size);
+    }
+
+  composite->set_completed (true);
+  push (std::move (composite));
+}
+
 void
 dwarf_expr_context::eval (const gdb_byte *addr, size_t len)
 {
@@ -4161,6 +4310,17 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 	    break;
 	  }
 
+	case DW_OP_LLVM_select_bit_piece:
+	  {
+	    uint64_t piece_bit_size, pieces_count;
+
+	    /* Record the piece.  */
+	    op_ptr = safe_read_uleb128 (op_ptr, op_end, &piece_bit_size);
+	    op_ptr = safe_read_uleb128 (op_ptr, op_end, &pieces_count);
+	    create_select_composite (piece_bit_size, pieces_count);
+	    break;
+	  }
+
 	default:
 	  error (_("Unhandled dwarf expression opcode 0x%x"), op);
 	}
diff --git a/gdb/dwarf2/loc.c b/gdb/dwarf2/loc.c
index d8bcd542776..071baad76d1 100644
--- a/gdb/dwarf2/loc.c
+++ b/gdb/dwarf2/loc.c
@@ -1955,6 +1955,7 @@ dwarf2_get_symbol_read_needs (gdb::array_view<const gdb_byte> expr,
 
 	case DW_OP_bit_piece:
 	case DW_OP_LLVM_extend:
+	case DW_OP_LLVM_select_bit_piece:
 	  op_ptr = safe_skip_leb128 (op_ptr, expr_end);
 	  op_ptr = safe_skip_leb128 (op_ptr, expr_end);
 	  break;
@@ -3679,6 +3680,17 @@ disassemble_dwarf_expression (struct ui_file *stream,
 	                      pulongest (ul), pulongest (count));
 	  }
 	  break;
+
+	case DW_OP_LLVM_select_bit_piece:
+	  {
+	    uint64_t count;
+
+	    data = safe_read_uleb128 (data, end, &ul);
+	    data = safe_read_uleb128 (data, end, &count);
+	    fprintf_filtered (stream, " piece size %s (bits) pieces count %s",
+			      pulongest (ul), pulongest (count));
+	  }
+	  break;
 	}
 
       fprintf_filtered (stream, "\n");
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-llvm-select-bit-piece.exp b/gdb/testsuite/gdb.dwarf2/dw2-llvm-select-bit-piece.exp
new file mode 100644
index 00000000000..c5ed6efbd75
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-llvm-select-bit-piece.exp
@@ -0,0 +1,138 @@
+# Copyright (C) 2017-2021 Free Software Foundation, Inc.
+# Copyright (C) 2020-2021 Advanced Micro Devices, Inc. All rights reserved.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test the new DW_OP_LLVM_select_bit_piece operation.
+#
+# The test uses a composite location description, where all the pieces
+# are selected from two registers in odd/even pattern using the new
+# operation.
+
+load_lib dwarf.exp
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+if {![dwarf2_support]} {
+    return 0
+}
+
+# Choose suitable integer registers for the test.
+
+set dwarf_regnum {0 1}
+
+if { [is_aarch64_target] } {
+    set regname {x0 x1}
+} elseif { [is_aarch32_target]
+	   || [istarget "s390*-*-*" ]
+	   || [istarget "powerpc*-*-*"]
+	   || [istarget "rs6000*-*-aix*"] } {
+    set regname {r0 r1}
+} elseif { [is_x86_like_target] } {
+    set regname {eax ecx}
+} elseif { [is_amd64_regs_target] } {
+    set regname {rax rdx}
+} else {
+    verbose "Skipping $gdb_test_file_name."
+    return
+}
+
+standard_testfile var-access.c ${gdb_test_file_name}-dw.S
+
+# Make some DWARF for the test.
+
+set asm_file [standard_output_file $srcfile2]
+Dwarf::assemble $asm_file {
+    global dwarf_regnum regname srcdir subdir srcfile
+    set buf_src [gdb_target_symbol buf]
+
+    set main_result [function_range main ${srcdir}/${subdir}/${srcfile}]
+    set main_start [lindex $main_result 0]
+    set main_length [lindex $main_result 1]
+
+    cu {} {
+	DW_TAG_compile_unit {
+	    {DW_AT_name var-access.c}
+	    {DW_AT_comp_dir /tmp}
+	} {
+	    declare_labels int_type_label char_type_label array_type_label
+
+	    # define char type
+	    char_type_label: DW_TAG_base_type {
+		{DW_AT_name "char"}
+		{DW_AT_encoding @DW_ATE_signed}
+		{DW_AT_byte_size 1 DW_FORM_sdata}
+	    }
+
+	    int_type_label: DW_TAG_base_type {
+		{DW_AT_name "int"}
+		{DW_AT_encoding @DW_ATE_signed}
+		{DW_AT_byte_size 4 DW_FORM_sdata}
+	    }
+
+	    array_type_label: DW_TAG_array_type {
+		{DW_AT_type :$char_type_label}
+	    } {
+		DW_TAG_subrange_type {
+		    {DW_AT_type :$int_type_label}
+		    {DW_AT_upper_bound 7 DW_FORM_udata}
+		}
+	    }
+
+	    DW_TAG_subprogram {
+		{DW_AT_name main}
+		{DW_AT_low_pc $main_start addr}
+		{DW_AT_high_pc $main_length data8}
+	    } {
+
+		# Odd array elements are in first byte of REGNAME 0 register,
+		# while even elements are in first byte of REGNAME 1 register.
+		DW_TAG_variable {
+		    {DW_AT_name var_array}
+		    {DW_AT_type :$array_type_label}
+		    {DW_AT_location {
+			DW_OP_regx [lindex $dwarf_regnum 0]
+			DW_OP_LLVM_extend 8 8
+                        DW_OP_regx [lindex $dwarf_regnum 1]
+			DW_OP_LLVM_extend 8 8
+			DW_OP_constu 0xaa
+			DW_OP_LLVM_select_bit_piece 8 8
+		    } SPECIAL_expr}
+		}
+	    }
+	}
+    }
+}
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} \
+     [list $srcfile $asm_file] {nodebug}] } {
+    return -1
+}
+
+if ![runto_main] {
+    return -1
+}
+
+gdb_test_no_output "set var \$[lindex $regname 0] = 0x04030201" "init reg 0"
+gdb_test_no_output "set var \$[lindex $regname 1] = 0x01020304" "init reg 1"
+
+# Determine byte order.
+set endian [get_endianness]
+
+switch $endian {
+	little {set val "0x1, 0x4, 0x1, 0x4, 0x1, 0x4, 0x1, 0x4"}
+	big {set val "0x4, 0x1, 0x4, 0x1, 0x4, 0x1, 0x4, 0x1"}
+}
+
+gdb_test "print/x var_array" " = \\{${val}\\}" "var_array print"
+
diff --git a/gdb/testsuite/lib/dwarf.exp b/gdb/testsuite/lib/dwarf.exp
index d2f3445c926..3bb9bdbd3d4 100644
--- a/gdb/testsuite/lib/dwarf.exp
+++ b/gdb/testsuite/lib/dwarf.exp
@@ -1230,6 +1230,11 @@ namespace eval Dwarf {
 		    _op .uleb128 [lindex $line 2]
 		}
 
+		DW_OP_LLVM_select_bit_piece {
+		    _op .uleb128 [lindex $line 1]
+		    _op .uleb128 [lindex $line 2]
+		}
+
 		default {
 		    if {[llength $line] > 1} {
 			error "Unimplemented: operands in location for $opcode"
diff --git a/include/dwarf2.def b/include/dwarf2.def
index 3d1d831d0fb..abc1125df2c 100644
--- a/include/dwarf2.def
+++ b/include/dwarf2.def
@@ -711,6 +711,7 @@ DW_OP_DUP (DW_OP_LLVM_bit_offset, 0xe5)
 DW_OP (DW_OP_LLVM_undefined, 0xe7)
 DW_OP_DUP (DW_OP_LLVM_piece_end, 0xea)
 DW_OP (DW_OP_LLVM_extend, 0xeb)
+DW_OP (DW_OP_LLVM_select_bit_piece, 0xec)
 DW_END_OP
 
 DW_FIRST_ATE (DW_ATE_void, 0x0)
-- 
2.17.1


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

* Re: [PATCH v4 01/28] Add new register access interface to expr.c
  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
  0 siblings, 0 replies; 38+ messages in thread
From: Tom Tromey @ 2021-12-14 20:34 UTC (permalink / raw)
  To: Zoran Zaric via Gdb-patches

>>>>> "Zoran" == Zoran Zaric via Gdb-patches <gdb-patches@sourceware.org> writes:

Zoran> DWARF expression evaluator is currently using get_frame_register_bytes
Zoran> and put_frame_register_bytes interface for register access.

Zoran> The problem with evaluator using this interface is that it allows a
Zoran> bleed out register access.

Yeah, I think this a leftover from some ancient bug, or maybe a stabs
thing.  I agree it can probably be dropped.

Zoran> DWARF specification does not define this behavior, so a new simplified
Zoran> register access interface is needed instead.

This patch looks reasonable to me.

Zoran> 	* dwarf2/expr.c (read_from_register): New function.
Zoran> 	(write_to_register): New function.
Zoran> 	(rw_pieced_value): Now calls the read_from_register and
Zoran> 	write_to_register functions.

You don't need a ChangeLog entry any more.

Tom

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

* Re: [PATCH v4 02/28] Add new memory access interface to expr.c
  2021-11-05 11:38 ` [PATCH v4 02/28] Add new memory " Zoran Zaric
@ 2021-12-14 20:42   ` Tom Tromey
  0 siblings, 0 replies; 38+ messages in thread
From: Tom Tromey @ 2021-12-14 20:42 UTC (permalink / raw)
  To: Zoran Zaric via Gdb-patches

>>>>> "Zoran" == Zoran Zaric via Gdb-patches <gdb-patches@sourceware.org> writes:

Zoran> From: Zoran Zaric <Zoran.Zaric@amd.com>
Zoran> DWARF expression evaluator is currently using a few different
Zoran> interfaces for memory access: write_memory_with_notification,
Zoran> read_value_memory, read_memory.

Zoran> They all seem incosistent, while some of them even need a struct
Zoran> value typed argument to be present.

Zoran> This patch is simplifying that interface by replacing it with two new
Zoran> low level functions: read_from_memory and write_to_memory.

I kept thinking there must be a better way, like some existing API, but
I looked at the other callers of target_xfer_partial and I think in the
end I agree with the approach you took here.

This looks ok to me.  Thanks.

Tom

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

* Re: [PATCH v4 03/28] Add new classes that model DWARF stack element
  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
  0 siblings, 1 reply; 38+ messages in thread
From: Tom Tromey @ 2021-12-14 21:10 UTC (permalink / raw)
  To: Zoran Zaric via Gdb-patches

>>>>> "Zoran" == Zoran Zaric via Gdb-patches <gdb-patches@sourceware.org> writes:

Zoran> +   Types of locations descirbed can be: register location, memory

Typo, "described".

Zoran> +
Zoran> +class dwarf_memory final : public dwarf_location

This one needs a comment.

Otherwise this patch looks ok to me.

Tom

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

* Re: [PATCH v4 04/28] Add to_location method to dwarf_value class
  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
  0 siblings, 1 reply; 38+ messages in thread
From: Tom Tromey @ 2021-12-14 21:16 UTC (permalink / raw)
  To: Zoran Zaric via Gdb-patches

>>>>> "Zoran" == Zoran Zaric via Gdb-patches <gdb-patches@sourceware.org> writes:

Zoran> By allowing any location description to be on the DWARF stack, these
Zoran> implicit conversions are expected on per operation basis which means
Zoran> that the new dwarf_value class need to have a support for it.

I don't really follow the meaning of "location description" in this
comment.  For me this term refers to the expression in DWARF, but here
you seem to be using it to refer to some sort of value.

Zoran> This patch adds a conversion method from a dwarf_value object into a
Zoran> location description object.

Zoran> --- a/gdbsupport/common-utils.h
Zoran> +++ b/gdbsupport/common-utils.h
Zoran> @@ -206,4 +206,22 @@ extern int hex2bin (const char *hex, gdb_byte *bin, int count);
Zoran>  /* Like the above, but return a gdb::byte_vector.  */
Zoran>  gdb::byte_vector hex2bin (const char *hex);
 
Zoran> +#if __cplusplus >= 201402L
Zoran> +#include <memory>
Zoran> +
Zoran> +using std::make_unique;
Zoran> +#else
Zoran> +namespace gdb {
Zoran> +
Zoran> +/* Stolen from libstdc++ and adjusted, so probably fine license-wise.  */

I think it's fine to just document that this came from libstdc++.

I tend to think this should go in gdbsupport/gdb_unique_ptr.h.

Tom

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

* Re: [PATCH v4 05/28] Add to_value method to dwarf_location class
  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
  0 siblings, 1 reply; 38+ messages in thread
From: Tom Tromey @ 2021-12-14 21:34 UTC (permalink / raw)
  To: Zoran Zaric via Gdb-patches

>>>>> "Zoran" == Zoran Zaric via Gdb-patches <gdb-patches@sourceware.org> writes:

Zoran> Currently, we only know how to convert from a memory location
Zoran> description into a value, but it is resonable to expect a set
Zoran> of target hooks that would let the target decide on how to do
Zoran> other conversions in the future.

When would this be useful?

Anyway, this patch looks ok.

Tom

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

* Re: [PATCH v4 03/28] Add new classes that model DWARF stack element
  2021-12-14 21:10   ` Tom Tromey
@ 2022-01-12 10:23     ` Zoran Zaric
  0 siblings, 0 replies; 38+ messages in thread
From: Zoran Zaric @ 2022-01-12 10:23 UTC (permalink / raw)
  To: Tom Tromey, Zoran Zaric via Gdb-patches

Thank you for reviewing the patch series Tom.

> 
> Zoran> +   Types of locations descirbed can be: register location, memory
> 
> Typo, "described".
> 
> Zoran> +
> Zoran> +class dwarf_memory final : public dwarf_location
> 
> This one needs a comment.
> 
> Otherwise this patch looks ok to me.
> 
> Tom
> 

This will be fixed in the next iteration.

Zoran

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

* Re: [PATCH v4 04/28] Add to_location method to dwarf_value class
  2021-12-14 21:16   ` Tom Tromey
@ 2022-01-12 10:51     ` Zoran Zaric
  0 siblings, 0 replies; 38+ messages in thread
From: Zoran Zaric @ 2022-01-12 10:51 UTC (permalink / raw)
  To: Tom Tromey, Zoran Zaric via Gdb-patches

Thank you for reviewing the patch Tom.

> 
> Zoran> By allowing any location description to be on the DWARF stack, these
> Zoran> implicit conversions are expected on per operation basis which means
> Zoran> that the new dwarf_value class need to have a support for it.
> 
> I don't really follow the meaning of "location description" in this
> comment.  For me this term refers to the expression in DWARF, but here
> you seem to be using it to refer to some sort of value

I see your point.

In DWARF the term of location description is not a description of a real 
storage because that expression still needs to be evaluated in some context.

So in a sense, what I refer to as a location description, is in fact an 
"evaluated location description in a current context" or even an "arch 
storage description". As a full disclaimer here, a new entity behind 
this "arch storage description" term is still not a fully evaluated 
location in a same way how "struct value" objects are not that, but 
similarly they do carry with them a context needed to get there (in some 
later stage).

Maybe a more suitable term for it would be just a "location"?

> 
> Zoran> This patch adds a conversion method from a dwarf_value object into a
> Zoran> location description object.
> 
> Zoran> --- a/gdbsupport/common-utils.h
> Zoran> +++ b/gdbsupport/common-utils.h
> Zoran> @@ -206,4 +206,22 @@ extern int hex2bin (const char *hex, gdb_byte *bin, int count);
> Zoran>  /* Like the above, but return a gdb::byte_vector.  */
> Zoran>  gdb::byte_vector hex2bin (const char *hex);
> 
> Zoran> +#if __cplusplus >= 201402L
> Zoran> +#include <memory>
> Zoran> +
> Zoran> +using std::make_unique;
> Zoran> +#else
> Zoran> +namespace gdb {
> Zoran> +
> Zoran> +/* Stolen from libstdc++ and adjusted, so probably fine license-wise.  */
> 
> I think it's fine to just document that this came from libstdc++.
> 
> I tend to think this should go in gdbsupport/gdb_unique_ptr.h.
> 
> Tom
> 

That makes sense to me.

Thanks,
Zoran

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

* Re: [PATCH v4 05/28] Add to_value method to dwarf_location class
  2021-12-14 21:34   ` Tom Tromey
@ 2022-01-12 12:14     ` Zoran Zaric
  2022-01-12 18:42       ` Zoran Zaric
  0 siblings, 1 reply; 38+ messages in thread
From: Zoran Zaric @ 2022-01-12 12:14 UTC (permalink / raw)
  To: Tom Tromey, Zoran Zaric via Gdb-patches


> 
> Zoran> Currently, we only know how to convert from a memory location
> Zoran> description into a value, but it is resonable to expect a set
> Zoran> of target hooks that would let the target decide on how to do
> Zoran> other conversions in the future.
> 
> When would this be useful?
> 
> Anyway, this patch looks ok.
> 
> Tom
> 

This is a bit difficult question to answer.

 From the class design point, it is useful to have an unified interface 
for all DWARF stack elements.

Having the generality and flexibility of a location description being on 
the stack and using that in conjunction with DW_OP_call like operations 
(for refactoring), one could have a need to convert a resulting implicit 
location description into a value.

Also, there were some suggestions of operations that would use the value 
on the top of the stack as a register number or an index to a register 
bank. In that world, the expression could push a register location 
description (as a base of indexing), convert it to some kind of value 
representation, apply index calculation to it and then use that new 
operation on the result.

In reality, we (AMD) don't need that flexibility, but it made sense to 
me to not be over restrictive where I didn't needed to be.

Zoran

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

* Re: [PATCH v4 05/28] Add to_value method to dwarf_location class
  2022-01-12 12:14     ` Zoran Zaric
@ 2022-01-12 18:42       ` Zoran Zaric
  0 siblings, 0 replies; 38+ messages in thread
From: Zoran Zaric @ 2022-01-12 18:42 UTC (permalink / raw)
  To: Tom Tromey, Zoran Zaric via Gdb-patches

> 
> Also, there were some suggestions of operations that would use the value 
> on the top of the stack as a register number or an index to a register 
> bank. In that world, the expression could push a register location 
> description (as a base of indexing), convert it to some kind of value 
> representation, apply index calculation to it and then use that new 
> operation on the result.
> 

To be clear here, I am not suggesting for anyone to do this because that 
would mean that there would be a target specific conversion from a 
register location into a DWARF register numbering value or (even worse) 
to the architecture register numbering and then apply index calculation 
which again either needs to have pre-baked knowledge of the DWARF 
register to arch register mapping or assume that the mapping was already 
by the conversion.

So all in all a very BAD example from my part and DWARF should never be 
extended/used like that, but I guess my point was that I didn't want to 
restrict the implementation more then it was needed.

However, I could just remove that comment from the commit message to 
reduce the confusion and then if we find that there is a usable 
conversion (like from the implicit location example) we can just add it 
in later.

Zoran

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

end of thread, other threads:[~2022-01-12 18:43 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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 ` [PATCH v4 15/28] Add to_gdb_value method to DWARF entry class Zoran Zaric
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

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