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

Based on gdb master: f19c3684a6db145f57048bff5485fec6e3dd0f76

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 entry classes
  Add to_value method to DWARF entry classes
  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                             | 4229 ++++++++++++-----
 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                                   |   48 +-
 gdb/testsuite/gdb.dwarf2/dw2-llvm-extend.exp  |  148 +
 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                                  |  129 +-
 gdb/value.c                                   |   68 +-
 gdb/value.h                                   |    4 +-
 include/dwarf2.def                            |    8 +
 22 files changed, 4381 insertions(+), 1505 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] 62+ messages in thread

* [PATCH v3 01/28] Add new register access interface to expr.c
  2021-10-14  9:32 [PATCH v3 00/28] Allow location description on the DWARF stack Zoran Zaric
@ 2021-10-14  9:32 ` Zoran Zaric
  2021-10-14  9:32 ` [PATCH v3 02/28] Add new memory " Zoran Zaric
                   ` (27 subsequent siblings)
  28 siblings, 0 replies; 62+ messages in thread
From: Zoran Zaric @ 2021-10-14  9:32 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 0f05f889e2a..3dfba38bdb3 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] 62+ messages in thread

* [PATCH v3 02/28] Add new memory access interface to expr.c
  2021-10-14  9:32 [PATCH v3 00/28] Allow location description on the DWARF stack Zoran Zaric
  2021-10-14  9:32 ` [PATCH v3 01/28] Add new register access interface to expr.c Zoran Zaric
@ 2021-10-14  9:32 ` Zoran Zaric
  2021-10-14  9:32 ` [PATCH v3 03/28] Add new classes that model DWARF stack element Zoran Zaric
                   ` (26 subsequent siblings)
  28 siblings, 0 replies; 62+ messages in thread
From: Zoran Zaric @ 2021-10-14  9:32 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 3dfba38bdb3..c0ca78ce236 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] 62+ messages in thread

* [PATCH v3 03/28] Add new classes that model DWARF stack element
  2021-10-14  9:32 [PATCH v3 00/28] Allow location description on the DWARF stack Zoran Zaric
  2021-10-14  9:32 ` [PATCH v3 01/28] Add new register access interface to expr.c Zoran Zaric
  2021-10-14  9:32 ` [PATCH v3 02/28] Add new memory " Zoran Zaric
@ 2021-10-14  9:32 ` Zoran Zaric
  2021-10-21 23:43   ` Lancelot SIX
  2021-10-14  9:32 ` [PATCH v3 04/28] Add to_location method to DWARF entry classes Zoran Zaric
                   ` (25 subsequent siblings)
  28 siblings, 1 reply; 62+ messages in thread
From: Zoran Zaric @ 2021-10-14  9:32 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 | 234 ++++++++++++++++++++++++++++++++++++++++++++++
 gdb/value.c       |   2 +-
 gdb/value.h       |   2 +
 3 files changed, 237 insertions(+), 1 deletion(-)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index c0ca78ce236..f44dfd1b260 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -271,6 +271,240 @@ 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
+{
+public:
+  /* Not expected to be called on it's own.  */
+  dwarf_entry () = default;
+
+  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
+{
+public:
+  /* Not expected to be called on it's own.  */
+  dwarf_location (gdbarch *arch, LONGEST offset)
+    : m_arch (arch), m_offset (offset)
+  {}
+
+  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 : 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_unsigned_long (m_contents.data (), type, value);
+  }
+
+  gdb::array_view<const gdb_byte> contents () const
+  {
+    return m_contents;
+  }
+
+  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 bb2adae0a51..0623d29a595 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -3465,7 +3465,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 45012372dbf..a01dc8de9f7 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] 62+ messages in thread

* [PATCH v3 04/28] Add to_location method to DWARF entry classes
  2021-10-14  9:32 [PATCH v3 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (2 preceding siblings ...)
  2021-10-14  9:32 ` [PATCH v3 03/28] Add new classes that model DWARF stack element Zoran Zaric
@ 2021-10-14  9:32 ` Zoran Zaric
  2021-10-22 21:21   ` Lancelot SIX
  2021-10-14  9:32 ` [PATCH v3 05/28] Add to_value " Zoran Zaric
                   ` (24 subsequent siblings)
  28 siblings, 1 reply; 62+ messages in thread
From: Zoran Zaric @ 2021-10-14  9:32 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 entry classes need to have a support for those.

This patch adds a conversion method from any DWARF entry object into a
location description object.

gdb/ChangeLog:

        * dwarf2/expr.c (class dwarf_value::to_location): New method.
---
 gdb/dwarf2/expr.c | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index f44dfd1b260..5d443edfd9d 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -36,6 +36,16 @@
 #include "inferior.h"
 #include "observable.h"
 
+/* Stolen from libstdc++ and adjusted, so probably fine license-wise.
+   Could be added in gdbsupport.  */
+
+template<typename _Tp, typename ... _Args>
+std::unique_ptr<_Tp>
+make_unique (_Args &&... __args)
+{
+  return std::unique_ptr<_Tp> (new _Tp (std::forward<_Args>(__args)...));
+}
+
 /* Cookie for gdbarch data.  */
 
 static struct gdbarch_data *dwarf_arch_cookie;
@@ -271,6 +281,9 @@ write_to_memory (CORE_ADDR address, const gdb_byte *buffer,
 					 length, buffer);
 }
 
+class dwarf_location;
+class dwarf_memory;
+
 /* Base class that describes entries found on a DWARF expression
    evaluation stack.  */
 
@@ -283,6 +296,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.
 
@@ -330,6 +345,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 : public dwarf_entry
@@ -366,6 +383,10 @@ class dwarf_value : 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;
@@ -403,6 +424,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
-- 
2.17.1


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

* [PATCH v3 05/28] Add to_value method to DWARF entry classes
  2021-10-14  9:32 [PATCH v3 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (3 preceding siblings ...)
  2021-10-14  9:32 ` [PATCH v3 04/28] Add to_location method to DWARF entry classes Zoran Zaric
@ 2021-10-14  9:32 ` Zoran Zaric
  2021-10-14  9:32 ` [PATCH v3 06/28] Add read method to location description classes Zoran Zaric
                   ` (23 subsequent siblings)
  28 siblings, 0 replies; 62+ messages in thread
From: Zoran Zaric @ 2021-10-14  9:32 UTC (permalink / raw)
  To: gdb-patches

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

Following the idea from the last patch this patch is adding another
conversion method from any DWARF entry 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 5d443edfd9d..56f17f52756 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -100,6 +100,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
@@ -283,6 +291,7 @@ write_to_memory (CORE_ADDR address, const gdb_byte *buffer,
 
 class dwarf_location;
 class dwarf_memory;
+class dwarf_value;
 
 /* Base class that describes entries found on a DWARF expression
    evaluation stack.  */
@@ -330,6 +339,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;
@@ -395,6 +414,8 @@ class dwarf_value : 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.  */
@@ -419,6 +440,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;
@@ -439,6 +462,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] 62+ messages in thread

* [PATCH v3 06/28] Add read method to location description classes
  2021-10-14  9:32 [PATCH v3 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (4 preceding siblings ...)
  2021-10-14  9:32 ` [PATCH v3 05/28] Add to_value " Zoran Zaric
@ 2021-10-14  9:32 ` Zoran Zaric
  2021-10-25 18:33   ` Lancelot SIX
  2021-10-14  9:32 ` [PATCH v3 07/28] Add write " Zoran Zaric
                   ` (22 subsequent siblings)
  28 siblings, 1 reply; 62+ messages in thread
From: Zoran Zaric @ 2021-10-14  9:32 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 56f17f52756..3f3e09db7cc 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -289,6 +289,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] == NULL)
+    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_memory;
 class dwarf_value;
@@ -349,6 +379,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;
@@ -426,6 +477,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
@@ -442,6 +501,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;
@@ -468,6 +532,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
@@ -477,11 +581,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 == NULL)
+    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.  */
@@ -497,6 +646,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;
@@ -505,6 +658,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
@@ -520,6 +712,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;
@@ -534,6 +730,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) + 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
@@ -549,6 +783,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.  */
@@ -570,6 +808,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.  */
@@ -1185,27 +1467,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] 62+ messages in thread

* [PATCH v3 07/28] Add write method to location description classes
  2021-10-14  9:32 [PATCH v3 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (5 preceding siblings ...)
  2021-10-14  9:32 ` [PATCH v3 06/28] Add read method to location description classes Zoran Zaric
@ 2021-10-14  9:32 ` Zoran Zaric
  2021-10-25 20:21   ` Lancelot SIX
  2021-10-14  9:32 ` [PATCH v3 08/28] Add deref " Zoran Zaric
                   ` (21 subsequent siblings)
  28 siblings, 1 reply; 62+ messages in thread
From: Zoran Zaric @ 2021-10-14  9:32 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 opeque 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 3f3e09db7cc..83a2db028ca 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -400,6 +400,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;
@@ -485,6 +507,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
@@ -506,6 +536,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;
@@ -572,6 +607,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;
+
+  total_bits_to_skip += m_bit_suboffset;
+  *optimized = 0;
+
+  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
@@ -585,6 +676,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;
@@ -631,6 +727,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 == NULL)
+    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.  */
@@ -650,6 +793,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;
@@ -716,6 +868,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;
@@ -787,6 +948,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.  */
@@ -852,6 +1018,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] 62+ messages in thread

* [PATCH v3 08/28] Add deref method to location description classes
  2021-10-14  9:32 [PATCH v3 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (6 preceding siblings ...)
  2021-10-14  9:32 ` [PATCH v3 07/28] Add write " Zoran Zaric
@ 2021-10-14  9:32 ` Zoran Zaric
  2021-10-25 22:31   ` Lancelot SIX
  2021-10-14  9:32 ` [PATCH v3 09/28] Add read_from_gdb_value method to dwarf_location Zoran Zaric
                   ` (20 subsequent siblings)
  28 siblings, 1 reply; 62+ messages in thread
From: Zoran Zaric @ 2021-10-14  9:32 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 an universal method that model 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 | 121 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 121 insertions(+)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index 83a2db028ca..87caba5fd62 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -422,6 +422,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 then the TYPE type size.
+     If SIZE is smaller then 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;
@@ -489,6 +501,43 @@ class dwarf_value : 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 do read-modify-write to "
+		   "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.  */
@@ -541,6 +590,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;
@@ -663,6 +717,73 @@ 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;
+      /* Using second buffer here because the copy_bitwise
+	 doesn't support in place copy.  */
+      gdb::byte_vector temp_buf (this_size);
+
+      if (offset < addr_info->valaddr.size ()
+	  && offset + this_size <= addr_info->valaddr.size ())
+	{
+	  memcpy (temp_buf.data (), addr_info->valaddr.data (), 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 do read-modify-write to "
+		     "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] 62+ messages in thread

* [PATCH v3 09/28] Add read_from_gdb_value method to dwarf_location
  2021-10-14  9:32 [PATCH v3 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (7 preceding siblings ...)
  2021-10-14  9:32 ` [PATCH v3 08/28] Add deref " Zoran Zaric
@ 2021-10-14  9:32 ` Zoran Zaric
  2021-10-14  9:32 ` [PATCH v3 10/28] Add write_to_gdb_value " Zoran Zaric
                   ` (19 subsequent siblings)
  28 siblings, 0 replies; 62+ messages in thread
From: Zoran Zaric @ 2021-10-14  9:32 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 87caba5fd62..03c3d7306e2 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -434,6 +434,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;
@@ -451,6 +467,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), 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 : public dwarf_entry
@@ -998,6 +1039,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;
@@ -1074,6 +1125,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.  */
@@ -1184,6 +1240,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] 62+ messages in thread

* [PATCH v3 10/28] Add write_to_gdb_value method to dwarf_location
  2021-10-14  9:32 [PATCH v3 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (8 preceding siblings ...)
  2021-10-14  9:32 ` [PATCH v3 09/28] Add read_from_gdb_value method to dwarf_location Zoran Zaric
@ 2021-10-14  9:32 ` Zoran Zaric
  2021-10-14  9:32 ` [PATCH v3 11/28] Add is_implicit_ptr_at " Zoran Zaric
                   ` (18 subsequent siblings)
  28 siblings, 0 replies; 62+ messages in thread
From: Zoran Zaric @ 2021-10-14  9:32 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 03c3d7306e2..bf8be951673 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -450,6 +450,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;
@@ -492,6 +508,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), 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 : public dwarf_entry
@@ -1049,6 +1084,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;
@@ -1130,6 +1171,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.  */
@@ -1283,6 +1329,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] 62+ messages in thread

* [PATCH v3 11/28] Add is_implicit_ptr_at method to dwarf_location
  2021-10-14  9:32 [PATCH v3 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (9 preceding siblings ...)
  2021-10-14  9:32 ` [PATCH v3 10/28] Add write_to_gdb_value " Zoran Zaric
@ 2021-10-14  9:32 ` Zoran Zaric
  2021-10-14  9:32 ` [PATCH v3 12/28] Add indirect_implicit_ptr to dwarf_location class Zoran Zaric
                   ` (17 subsequent siblings)
  28 siblings, 0 replies; 62+ messages in thread
From: Zoran Zaric @ 2021-10-14  9:32 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 bf8be951673..aa36a992e09 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -466,6 +466,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;
@@ -1090,6 +1098,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;
@@ -1176,6 +1189,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.  */
@@ -1372,6 +1387,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] 62+ messages in thread

* [PATCH v3 12/28] Add indirect_implicit_ptr to dwarf_location class
  2021-10-14  9:32 [PATCH v3 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (10 preceding siblings ...)
  2021-10-14  9:32 ` [PATCH v3 11/28] Add is_implicit_ptr_at " Zoran Zaric
@ 2021-10-14  9:32 ` Zoran Zaric
  2021-10-26 20:52   ` Lancelot SIX
  2021-10-14  9:32 ` [PATCH v3 13/28] Add is_optimized_out " Zoran Zaric
                   ` (16 subsequent siblings)
  28 siblings, 1 reply; 62+ messages in thread
From: Zoran Zaric @ 2021-10-14  9:32 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 then 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 then 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 aa36a992e09..af84710b054 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -474,6 +474,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;
@@ -1103,6 +1121,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;
@@ -1155,6 +1178,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
@@ -1191,6 +1225,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.  */
@@ -1424,6 +1463,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] 62+ messages in thread

* [PATCH v3 13/28] Add is_optimized_out to dwarf_location class
  2021-10-14  9:32 [PATCH v3 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (11 preceding siblings ...)
  2021-10-14  9:32 ` [PATCH v3 12/28] Add indirect_implicit_ptr to dwarf_location class Zoran Zaric
@ 2021-10-14  9:32 ` Zoran Zaric
  2021-10-14  9:32 ` [PATCH v3 14/28] Add new computed struct value callback interface Zoran Zaric
                   ` (15 subsequent siblings)
  28 siblings, 0 replies; 62+ messages in thread
From: Zoran Zaric @ 2021-10-14  9:32 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 af84710b054..1b6622d5f59 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -492,6 +492,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;
@@ -666,6 +681,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
@@ -904,6 +926,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;
@@ -997,6 +1023,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.  */
@@ -1025,6 +1069,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;
@@ -1230,6 +1281,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.  */
@@ -1497,6 +1552,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] 62+ messages in thread

* [PATCH v3 14/28] Add new computed struct value callback interface
  2021-10-14  9:32 [PATCH v3 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (12 preceding siblings ...)
  2021-10-14  9:32 ` [PATCH v3 13/28] Add is_optimized_out " Zoran Zaric
@ 2021-10-14  9:32 ` Zoran Zaric
  2021-10-26 22:50   ` Lancelot SIX
  2021-10-14  9:32 ` [PATCH v3 15/28] Add to_gdb_value method to DWARF entry class Zoran Zaric
                   ` (14 subsequent siblings)
  28 siblings, 1 reply; 62+ messages in thread
From: Zoran Zaric @ 2021-10-14  9:32 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 | 307 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 307 insertions(+)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index 1b6622d5f59..e33be7e7c1c 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -323,6 +323,92 @@ class dwarf_location;
 class dwarf_memory;
 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;
+
+  frame_id get_frame_id () const
+  {
+    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 = NULL;
+};
+
 /* Base class that describes entries found on a DWARF expression
    evaluation stack.  */
 
@@ -524,6 +610,11 @@ class dwarf_location : public dwarf_entry
 
 using dwarf_location_up = std::unique_ptr<dwarf_location>;
 
+const dwarf_location &computed_closure::get_location () const
+{
+  return *m_location;
+}
+
 void
 dwarf_location::read_from_gdb_value (frame_info *frame, struct value *value,
 				     int value_bit_offset,
@@ -1594,6 +1685,222 @@ 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);
+  bool big_endian = type_byte_order (value_type (v)) == BFD_ENDIAN_BIG;
+  const dwarf_location &location = closure->get_location ();
+
+  if (from == NULL)
+    {
+      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"));
+    }
+
+  ULONGEST bits_to_skip = HOST_CHAR_BIT * 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 * value_offset (value_parent (v))
+		       + value_bitpos (v);
+      if (from != NULL && 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 (value_type (v));
+
+  frame_info *frame = closure->get_frame ();
+
+  if (frame == NULL)
+    frame = frame_find_by_id (closure->get_frame_id ());
+
+  if (from == NULL)
+    {
+      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 contains 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);
+  bool big_endian = type_byte_order (value_type (v)) == BFD_ENDIAN_BIG;
+  const dwarf_location &location = closure->get_location ();
+
+  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"));
+
+  ULONGEST bits_to_skip = HOST_CHAR_BIT * 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 * value_offset (value_parent (v))
+		      + value_bitpos (v);
+      max_bit_size = value_bitsize (v);
+    }
+  else
+    max_bit_size = HOST_CHAR_BIT * TYPE_LENGTH (value_type (v));
+
+  frame_info *frame = closure->get_frame ();
+
+  if (frame == NULL)
+    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)
+{
+  LONGEST total_bit_offset = bit_offset + HOST_CHAR_BIT * value_offset (value);
+
+  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 NULL;
+
+  LONGEST bit_length = HOST_CHAR_BIT * TYPE_LENGTH (type);
+  LONGEST bit_offset = HOST_CHAR_BIT * 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),
+			      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),
+				    TARGET_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 NULL;
+    }
+}
+
 struct piece_closure
 {
   /* Reference count.  */
-- 
2.17.1


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

* [PATCH v3 15/28] Add to_gdb_value method to DWARF entry class
  2021-10-14  9:32 [PATCH v3 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (13 preceding siblings ...)
  2021-10-14  9:32 ` [PATCH v3 14/28] Add new computed struct value callback interface Zoran Zaric
@ 2021-10-14  9:32 ` Zoran Zaric
  2021-10-14  9:32 ` [PATCH v3 16/28] Change DWARF stack to use new dwarf_entry classes Zoran Zaric
                   ` (13 subsequent siblings)
  28 siblings, 0 replies; 62+ messages in thread
From: Zoran Zaric @ 2021-10-14  9:32 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 | 280 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 280 insertions(+)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index e33be7e7c1c..a34a5037686 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -441,6 +441,10 @@ class dwarf_location : public dwarf_entry
 
   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)
   {
@@ -593,6 +597,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;
@@ -680,6 +694,16 @@ class dwarf_value : public dwarf_entry
     pack_unsigned_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),
+					      TYPE_LENGTH (m_type));
+    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;
@@ -699,12 +723,22 @@ class dwarf_value : 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>;
@@ -746,6 +780,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),
+	  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.  */
@@ -757,6 +808,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
@@ -779,6 +835,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
@@ -788,6 +857,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;
@@ -810,6 +884,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;
@@ -999,6 +1077,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
@@ -1008,6 +1107,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;
@@ -1021,6 +1125,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;
@@ -1132,6 +1241,51 @@ 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 == NULL)
+    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));
+  LONGEST retval_offset = value_offset (retval);
+
+  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);
+  else
+    set_value_offset (retval, retval_offset + m_offset);
+
+  /* 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.  */
@@ -1147,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;
@@ -1167,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;
@@ -1214,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),
+	  (void *) (m_contents.data () + subobj_offset), subtype_len);
+
+  return retval;
+}
+
 /* Implicit pointer location description entry.  */
 
 class dwarf_implicit_pointer final : public dwarf_location
@@ -1229,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;
@@ -1268,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;
@@ -1331,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
@@ -1340,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);
@@ -1376,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.  */
@@ -1386,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;
   };
@@ -1685,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] 62+ messages in thread

* [PATCH v3 16/28] Change DWARF stack to use new dwarf_entry classes
  2021-10-14  9:32 [PATCH v3 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (14 preceding siblings ...)
  2021-10-14  9:32 ` [PATCH v3 15/28] Add to_gdb_value method to DWARF entry class Zoran Zaric
@ 2021-10-14  9:32 ` Zoran Zaric
  2021-10-31 17:58   ` Lancelot SIX
  2021-10-14  9:32 ` [PATCH v3 17/28] Remove old computed struct value callbacks Zoran Zaric
                   ` (12 subsequent siblings)
  28 siblings, 1 reply; 62+ messages in thread
From: Zoran Zaric @ 2021-10-14  9:32 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                             | 1364 ++++++++---------
 gdb/dwarf2/expr.h                             |   91 +-
 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, 701 insertions(+), 760 deletions(-)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index a34a5037686..8c116cc60b6 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -409,20 +409,6 @@ class computed_closure : public refcounted_object
   frame_info *m_frame = NULL;
 };
 
-/* Base class that describes entries found on a DWARF expression
-   evaluation stack.  */
-
-class dwarf_entry
-{
-public:
-  /* Not expected to be called on it's own.  */
-  dwarf_entry () = default;
-
-  virtual ~dwarf_entry () = default;
-};
-
-using dwarf_entry_up = std::unique_ptr<dwarf_entry>;
-
 /* Location description entry found on a DWARF expression evaluation
    stack.
 
@@ -441,6 +427,11 @@ class dwarf_location : public dwarf_entry
 
   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;
@@ -704,6 +695,11 @@ class dwarf_value : 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 +1961,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 a given 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 lesser 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)
 {
@@ -2181,6 +2289,53 @@ 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);
+
+  LONGEST offset = value_offset (value);
+
+  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) + 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.  */
@@ -2200,34 +2355,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
@@ -2809,43 +2936,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.  */
@@ -2889,7 +3020,6 @@ dwarf_expr_context::get_base_type (cu_offset die_cu_off)
 
   if (result == nullptr)
     error (_("Could not find type for operation"));
-
   return result;
 }
 
@@ -2920,31 +3050,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,
@@ -2997,7 +3102,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)
@@ -3006,148 +3110,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),
-		    value_contents_all (val) + 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);
-	    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.  */
@@ -3222,103 +3195,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),
-				     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
@@ -3365,7 +3303,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
@@ -3585,9 +3522,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);
@@ -3596,17 +3530,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.  */
@@ -3646,92 +3569,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.  */
@@ -3767,21 +3729,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:
 	  {
@@ -3790,19 +3754,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:
@@ -3813,20 +3786,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:
@@ -3860,78 +3835,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:
 	  {
@@ -3940,15 +3927,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:
@@ -3958,13 +3943,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:
@@ -3973,72 +3956,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:
@@ -4059,189 +4033,216 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
 	case DW_OP_ne:
 	  {
 	    /* Binary operations.  */
-	    struct value *first, *second;
-
-	    second = fetch (0);
-	    pop ();
+	    dwarf_value_up arg2 = to_value (pop (), address_type);
+	    dwarf_value_up arg1 = to_value (pop (), address_type);
 
-	    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:
 	  {
@@ -4249,16 +4250,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:
 	  {
@@ -4268,23 +4262,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:
 	  {
@@ -4292,8 +4287,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:
 	  {
@@ -4301,8 +4296,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:
 	  {
@@ -4310,15 +4305,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:
@@ -4338,7 +4341,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,
@@ -4351,7 +4354,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 "
@@ -4369,111 +4372,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));
+	      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..aaae381f4fe 100644
--- a/gdb/dwarf2/expr.h
+++ b/gdb/dwarf2/expr.h
@@ -25,6 +25,22 @@
 #include "leb128.h"
 #include "gdbtypes.h"
 
+/* Base class that describes entries found on a DWARF expression
+   evaluation stack.  */
+
+class dwarf_entry
+{
+public:
+  /* Not expected to be called on it's own.  */
+  dwarf_entry () = default;
+
+  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 +114,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 +123,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 +144,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 +155,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 +169,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 +207,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 8b81b5b2119..c6505e09bc5 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] 62+ messages in thread

* [PATCH v3 17/28] Remove old computed struct value callbacks
  2021-10-14  9:32 [PATCH v3 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (15 preceding siblings ...)
  2021-10-14  9:32 ` [PATCH v3 16/28] Change DWARF stack to use new dwarf_entry classes Zoran Zaric
@ 2021-10-14  9:32 ` Zoran Zaric
  2021-10-14  9:32 ` [PATCH v3 18/28] Comments cleanup between expr.h and expr.c Zoran Zaric
                   ` (11 subsequent siblings)
  28 siblings, 0 replies; 62+ messages in thread
From: Zoran Zaric @ 2021-10-14  9:32 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 8c116cc60b6..871c558e1a8 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -2336,548 +2336,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);
-      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);
-      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),
-			  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),
-			      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 aaae381f4fe..1f3507ba5db 100644
--- a/gdb/dwarf2/expr.h
+++ b/gdb/dwarf2/expr.h
@@ -43,78 +43,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] 62+ messages in thread

* [PATCH v3 18/28] Comments cleanup between expr.h and expr.c
  2021-10-14  9:32 [PATCH v3 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (16 preceding siblings ...)
  2021-10-14  9:32 ` [PATCH v3 17/28] Remove old computed struct value callbacks Zoran Zaric
@ 2021-10-14  9:32 ` Zoran Zaric
  2021-10-14  9:32 ` [PATCH v3 19/28] Remove dwarf_expr_context from expr.h interface Zoran Zaric
                   ` (10 subsequent siblings)
  28 siblings, 0 replies; 62+ messages in thread
From: Zoran Zaric @ 2021-10-14  9:32 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 871c558e1a8..d5ecc5b4a87 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -2394,7 +2394,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)
@@ -2402,7 +2402,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)
@@ -2412,7 +2412,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 ()
@@ -2425,7 +2425,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)
@@ -2653,7 +2653,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
@@ -2661,7 +2661,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)
@@ -2715,7 +2715,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)
@@ -2729,7 +2729,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,
@@ -2741,7 +2741,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,
@@ -2753,6 +2753,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)
 {
@@ -2762,9 +2764,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,
@@ -2792,8 +2792,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)
@@ -2833,10 +2832,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,
@@ -2894,8 +2890,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,
@@ -2920,9 +2915,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,
@@ -2962,8 +2955,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 1f3507ba5db..adf1f11c8ec 100644
--- a/gdb/dwarf2/expr.h
+++ b/gdb/dwarf2/expr.h
@@ -47,10 +47,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
@@ -95,13 +102,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
@@ -141,18 +173,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);
@@ -192,14 +238,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] 62+ messages in thread

* [PATCH v3 19/28] Remove dwarf_expr_context from expr.h interface
  2021-10-14  9:32 [PATCH v3 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (17 preceding siblings ...)
  2021-10-14  9:32 ` [PATCH v3 18/28] Comments cleanup between expr.h and expr.c Zoran Zaric
@ 2021-10-14  9:32 ` Zoran Zaric
  2021-10-14  9:32 ` [PATCH v3 20/28] Move read_addr_from_reg function to frame.c Zoran Zaric
                   ` (9 subsequent siblings)
  28 siblings, 0 replies; 62+ messages in thread
From: Zoran Zaric @ 2021-10-14  9:32 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  | 212 +++++++++++++++++++++++++++++++++++----------
 gdb/dwarf2/expr.h  | 164 +++++------------------------------
 gdb/dwarf2/frame.c |  14 ++-
 gdb/dwarf2/loc.c   |  23 +++--
 4 files changed, 213 insertions(+), 200 deletions(-)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index d5ecc5b4a87..1481d50584f 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -289,12 +289,8 @@ 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
@@ -409,6 +405,22 @@ class computed_closure : public refcounted_object
   frame_info *m_frame = NULL;
 };
 
+/* Base class that describes entries found on a DWARF expression
+   evaluation stack.  */
+
+class dwarf_entry
+{
+public:
+  /* Not expected to be called on it's own.  */
+  dwarf_entry () = default;
+
+  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.
 
@@ -2374,11 +2386,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 (),
@@ -2394,26 +2525,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 ()
 {
@@ -2425,8 +2542,6 @@ dwarf_expr_context::pop ()
   return entry;
 }
 
-/* See expr.h.  */
-
 dwarf_entry &
 dwarf_expr_context::fetch (int n)
 {
@@ -2437,8 +2552,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)
@@ -2465,24 +2578,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)
 {
@@ -2506,8 +2615,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,
@@ -2554,8 +2661,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)
@@ -2581,18 +2686,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);
@@ -2653,16 +2762,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)
 {
@@ -2714,9 +2819,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)
 {
@@ -2955,8 +3057,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)
@@ -3914,6 +4014,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 adf1f11c8ec..df097f8867d 100644
--- a/gdb/dwarf2/expr.h
+++ b/gdb/dwarf2/expr.h
@@ -25,149 +25,31 @@
 #include "leb128.h"
 #include "gdbtypes.h"
 
-/* Base class that describes entries found on a DWARF expression
-   evaluation stack.  */
-
-class dwarf_entry
-{
-public:
-  /* Not expected to be called on it's own.  */
-  dwarf_entry () = default;
-
-  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 0e5599353c4..d3f96ffca5a 100644
--- a/gdb/dwarf2/loc.c
+++ b/gdb/dwarf2/loc.c
@@ -1473,15 +1473,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)
     {
@@ -1552,23 +1552,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] 62+ messages in thread

* [PATCH v3 20/28] Move read_addr_from_reg function to frame.c
  2021-10-14  9:32 [PATCH v3 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (18 preceding siblings ...)
  2021-10-14  9:32 ` [PATCH v3 19/28] Remove dwarf_expr_context from expr.h interface Zoran Zaric
@ 2021-10-14  9:32 ` Zoran Zaric
  2021-10-14  9:32 ` [PATCH v3 21/28] Add frame info check to DW_OP_reg operations Zoran Zaric
                   ` (8 subsequent siblings)
  28 siblings, 0 replies; 62+ messages in thread
From: Zoran Zaric @ 2021-10-14  9:32 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 1481d50584f..5bec805a8fb 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -108,17 +108,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] 62+ messages in thread

* [PATCH v3 21/28] Add frame info check to DW_OP_reg operations
  2021-10-14  9:32 [PATCH v3 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (19 preceding siblings ...)
  2021-10-14  9:32 ` [PATCH v3 20/28] Move read_addr_from_reg function to frame.c Zoran Zaric
@ 2021-10-14  9:32 ` Zoran Zaric
  2021-10-14  9:32 ` [PATCH v3 22/28] Remove DWARF expression composition check Zoran Zaric
                   ` (7 subsequent siblings)
  28 siblings, 0 replies; 62+ messages in thread
From: Zoran Zaric @ 2021-10-14  9:32 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 5bec805a8fb..602a5186cfa 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -3270,6 +3270,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] 62+ messages in thread

* [PATCH v3 22/28] Remove DWARF expression composition check
  2021-10-14  9:32 [PATCH v3 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (20 preceding siblings ...)
  2021-10-14  9:32 ` [PATCH v3 21/28] Add frame info check to DW_OP_reg operations Zoran Zaric
@ 2021-10-14  9:32 ` Zoran Zaric
  2021-10-14  9:32 ` [PATCH v3 23/28] Add support for any location description in CFI Zoran Zaric
                   ` (6 subsequent siblings)
  28 siblings, 0 replies; 62+ messages in thread
From: Zoran Zaric @ 2021-10-14  9:32 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 602a5186cfa..20fb0e66c97 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -3282,7 +3282,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;
 	  }
@@ -3298,8 +3297,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;
 	  }
 
@@ -3311,9 +3308,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;
 	  }
 
@@ -3338,8 +3332,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] 62+ messages in thread

* [PATCH v3 23/28] Add support for any location description in CFI
  2021-10-14  9:32 [PATCH v3 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (21 preceding siblings ...)
  2021-10-14  9:32 ` [PATCH v3 22/28] Remove DWARF expression composition check Zoran Zaric
@ 2021-10-14  9:32 ` Zoran Zaric
  2021-10-31 22:58   ` Lancelot SIX
  2021-10-14  9:32 ` [PATCH v3 24/28] Add DWARF operations for byte and bit offset Zoran Zaric
                   ` (5 subsequent siblings)
  28 siblings, 1 reply; 62+ messages in thread
From: Zoran Zaric @ 2021-10-14  9:32 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        | 36 +++++++++++++++++++++++++------
 2 files changed, 61 insertions(+), 29 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 16673258373..3d85d2c7b59 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -1532,26 +1532,50 @@ 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))
+
+      /*  Compute value is a special new case.  The problem is that
+	  the computed callback mechanism only supports a struct
+	  value arguments, so we need to make one.  */
+      if (value != NULL && VALUE_LVAL (value) == lval_computed)
+	{
+	  const lval_funcs *funcs = value_computed_funcs (value);
+	  type * reg_type = register_type (gdbarch, regnum);
+
+	  if (funcs->write == NULL)
+	    error (_("Attempt to assign to an unmodifiable value."));
+
+	  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);
 
-	  memcpy ((char *) value_contents_writeable (value) + offset, myaddr,
-		  curr_len);
+	  memcpy ((char *) value_contents_writeable (value) + offset,
+		  myaddr, curr_len);
 	  put_frame_register (frame, regnum, value_contents_raw (value));
-	  release_value (value);
 	}
 
+      if (value != NULL)
+	release_value (value);
+
       myaddr += curr_len;
       len -= curr_len;
       offset = 0;
-- 
2.17.1


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

* [PATCH v3 24/28] Add DWARF operations for byte and bit offset
  2021-10-14  9:32 [PATCH v3 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (22 preceding siblings ...)
  2021-10-14  9:32 ` [PATCH v3 23/28] Add support for any location description in CFI Zoran Zaric
@ 2021-10-14  9:32 ` Zoran Zaric
  2021-10-14  9:32 ` [PATCH v3 25/28] Add support for DW_OP_LLVM_undefined operation Zoran Zaric
                   ` (4 subsequent siblings)
  28 siblings, 0 replies; 62+ messages in thread
From: Zoran Zaric @ 2021-10-14  9:32 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                            |  39 ++-
 gdb/dwarf2/loc.c                             |   8 +
 gdb/f-lang.c                                 |   6 +-
 gdb/findvar.c                                |   4 +-
 gdb/frame.c                                  |  18 +-
 gdb/testsuite/gdb.dwarf2/dw2-llvm-offset.exp | 328 +++++++++++++++++++
 gdb/testsuite/lib/dwarf.exp                  |   4 +
 gdb/valops.c                                 | 129 +++++---
 gdb/value.c                                  |  66 ++--
 gdb/value.h                                  |   2 +-
 include/dwarf2.def                           |   4 +
 13 files changed, 535 insertions(+), 81 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 98718bcc98b..42162dcaed4 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 20fb0e66c97..de8a618b941 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -1092,6 +1092,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;
 }
 
@@ -1265,6 +1266,8 @@ dwarf_register::to_gdb_value (frame_info *frame, struct type *type,
   else
     set_value_offset (retval, retval_offset + m_offset);
 
+  set_value_bitpos (retval, m_bit_suboffset);
+
   /* Get the data.  */
   read_frame_register_value (retval, frame);
 
@@ -1276,7 +1279,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;
     }
 
@@ -3987,6 +3990,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 d3f96ffca5a..4ac2056eb9a 100644
--- a/gdb/dwarf2/loc.c
+++ b/gdb/dwarf2/loc.c
@@ -1923,6 +1923,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:
@@ -1940,6 +1942,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;
 
@@ -3656,6 +3659,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 16ec9e04044..ff5d8354906 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 56edbdba578..191f976eea7 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 3d85d2c7b59..65b35c55a0e 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -1496,7 +1496,9 @@ get_frame_register_bytes (frame_info *frame, int regnum,
 	      return false;
 	    }
 
-	  memcpy (myaddr, value_contents_all (value) + offset, curr_len);
+	  memcpy (myaddr,
+		  value_contents_all (value) + value_offset (value) + offset,
+		  curr_len);
 	  release_value (value);
 	}
 
@@ -1530,16 +1532,24 @@ 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;
 
       const gdb_byte *myaddr = buffer.data ();
-
       /*  Compute value is a special new case.  The problem is that
 	  the computed callback mechanism only supports a struct
 	  value arguments, so we need to make one.  */
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 66f9844fe2e..ac943cb0419 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 f65479b8117..f1872e072d1 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -1037,20 +1037,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)
@@ -1067,6 +1078,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.
@@ -1138,7 +1153,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))
 	  {
@@ -1164,10 +1179,25 @@ 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),
+			  0, TYPE_LENGTH (type) * HOST_CHAR_BIT, big_endian);
+	    dest_buffer = buffer.data();
 	  }
 	else
 	  {
@@ -1183,7 +1213,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
@@ -1201,29 +1230,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,
@@ -1233,23 +1274,20 @@ 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),
+			  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));
+		gdbarch_value_to_register (arch, frame, VALUE_REGNUM (toval),
+					   type, value_contents (fromval));
 	      }
 	    else
 	      {
@@ -1257,8 +1295,7 @@ value_assign (struct value *toval, struct value *fromval)
 		  = gdb::make_array_view (value_contents (fromval),
 					  TYPE_LENGTH (type));
 		put_frame_register_bytes (frame, value_reg,
-					  value_offset (toval),
-					  contents);
+					  offset, contents);
 	      }
 	  }
 
@@ -1360,21 +1397,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),
-		     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),
+		     type_length_units (enclosing_type));
 
   return val;
 }
@@ -1723,7 +1761,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;
     }
@@ -1733,7 +1771,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;
 }
 
@@ -4002,7 +4041,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 0623d29a595..e3a3d573aaf 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -1313,9 +1313,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);
 
@@ -1334,17 +1335,29 @@ value_contents_copy_raw (struct value *dst, LONGEST dst_offset,
 					     TARGET_CHAR_BIT * length));
 
   /* Copy the data.  */
-  memcpy (value_contents_all_raw (dst) + dst_offset * unit_size,
-	  value_contents_all_raw (src) + 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) + dst_offset * unit_size, 0,
+		    value_contents_all_raw (src) + src_offset * unit_size,
+		    src_bit_offset, bit_length, big_endian);
+    }
+  else
+    memcpy (value_contents_all_raw (dst) + dst_offset * unit_size,
+	    value_contents_all_raw (src) + 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);
 }
 
@@ -1360,12 +1373,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
@@ -3078,7 +3093,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;
@@ -3113,7 +3128,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));
@@ -3720,7 +3735,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);
@@ -3902,9 +3917,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),
-			 type_length_units (type));
+    read_value_memory (val, value_bitpos (val), value_stack (val),
+		       addr, value_contents_all_raw (val),
+		       type_length_units (type));
 }
 
 /* Helper for value_fetch_lazy when the value is in a register.  */
@@ -3917,10 +3932,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);
@@ -3963,6 +3974,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))
@@ -3971,9 +3987,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 a01dc8de9f7..5a8662e409d 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] 62+ messages in thread

* [PATCH v3 25/28] Add support for DW_OP_LLVM_undefined operation
  2021-10-14  9:32 [PATCH v3 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (23 preceding siblings ...)
  2021-10-14  9:32 ` [PATCH v3 24/28] Add DWARF operations for byte and bit offset Zoran Zaric
@ 2021-10-14  9:32 ` Zoran Zaric
  2021-10-14  9:32 ` [PATCH v3 26/28] Add support for nested composite locations Zoran Zaric
                   ` (3 subsequent siblings)
  28 siblings, 0 replies; 62+ messages in thread
From: Zoran Zaric @ 2021-10-14  9:32 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 de8a618b941..dda9989629f 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -4024,6 +4024,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 4ac2056eb9a..5a16ba51848 100644
--- a/gdb/dwarf2/loc.c
+++ b/gdb/dwarf2/loc.c
@@ -1925,6 +1925,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] 62+ messages in thread

* [PATCH v3 26/28] Add support for nested composite locations
  2021-10-14  9:32 [PATCH v3 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (24 preceding siblings ...)
  2021-10-14  9:32 ` [PATCH v3 25/28] Add support for DW_OP_LLVM_undefined operation Zoran Zaric
@ 2021-10-14  9:32 ` Zoran Zaric
  2021-10-14  9:32 ` [PATCH v3 27/28] Add DW_OP_LLVM_extend DWARF operation Zoran Zaric
                   ` (2 subsequent siblings)
  28 siblings, 0 replies; 62+ messages in thread
From: Zoran Zaric @ 2021-10-14  9:32 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 dda9989629f..3cf4c78e4dc 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -1570,9 +1570,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;
@@ -1637,6 +1648,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
@@ -1649,6 +1663,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.  */
@@ -1694,6 +1711,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.  */
@@ -1946,14 +1966,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 ();
@@ -2445,13 +2467,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
@@ -2774,10 +2818,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);
@@ -2797,9 +2842,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);
@@ -4028,6 +4077,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 5a16ba51848..c93981e9721 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_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] 62+ messages in thread

* [PATCH v3 27/28] Add DW_OP_LLVM_extend DWARF operation
  2021-10-14  9:32 [PATCH v3 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (25 preceding siblings ...)
  2021-10-14  9:32 ` [PATCH v3 26/28] Add support for nested composite locations Zoran Zaric
@ 2021-10-14  9:32 ` Zoran Zaric
  2021-11-01 21:48   ` Lancelot SIX
  2021-10-14  9:32 ` [PATCH v3 28/28] Add DW_OP_LLVM_select_bit_piece " Zoran Zaric
  2021-11-05 11:54 ` [PATCH v3 00/28] Allow location description on the DWARF stack Zaric, Zoran (Zare)
  28 siblings, 1 reply; 62+ messages in thread
From: Zoran Zaric @ 2021-10-14  9:32 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                  |   4 +
 gdb/dwarf2/expr.c                            |  44 ++++++
 gdb/dwarf2/loc.c                             |  12 ++
 gdb/testsuite/gdb.dwarf2/dw2-llvm-extend.exp | 148 +++++++++++++++++++
 gdb/testsuite/lib/dwarf.exp                  |   5 +
 include/dwarf2.def                           |   1 +
 6 files changed, 214 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..2c5e13cfb6c 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_extend:
+	  stack_depth -= 2;
+	  break;
+
 	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 3cf4c78e4dc..711a5918946 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -2498,6 +2498,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);
@@ -2860,6 +2869,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)
 {
@@ -4090,6 +4123,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 c93981e9721..de3a904695a 100644
--- a/gdb/dwarf2/loc.c
+++ b/gdb/dwarf2/loc.c
@@ -1953,6 +1953,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;
@@ -3666,6 +3667,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..2a82eed02b8
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/dw2-llvm-extend.exp
@@ -0,0 +1,148 @@
+# 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_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 ac943cb0419..41415986e64 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] 62+ messages in thread

* [PATCH v3 28/28] Add DW_OP_LLVM_select_bit_piece DWARF operation
  2021-10-14  9:32 [PATCH v3 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (26 preceding siblings ...)
  2021-10-14  9:32 ` [PATCH v3 27/28] Add DW_OP_LLVM_extend DWARF operation Zoran Zaric
@ 2021-10-14  9:32 ` Zoran Zaric
  2021-11-01 22:25   ` Lancelot SIX
  2021-11-05 11:54 ` [PATCH v3 00/28] Allow location description on the DWARF stack Zaric, Zoran (Zare)
  28 siblings, 1 reply; 62+ messages in thread
From: Zoran Zaric @ 2021-10-14  9:32 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                   |   1 +
 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, 317 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 2c5e13cfb6c..5991760adbc 100644
--- a/gdb/compile/compile-loc2c.c
+++ b/gdb/compile/compile-loc2c.c
@@ -367,6 +367,7 @@ compute_stack_depth_worker (int start, int *need_tempvar,
 	  break;
 
 	case DW_OP_LLVM_extend:
+	case DW_OP_LLVM_select_bit_piece:
 	  stack_depth -= 2;
 	  break;
 
diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index 711a5918946..874a5d1923b 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.
@@ -621,6 +630,17 @@ const dwarf_location &computed_closure::get_location () const
   return *m_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,
@@ -1567,6 +1587,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);
@@ -1653,6 +1676,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,
@@ -2507,6 +2588,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);
@@ -2893,6 +2988,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)
 {
@@ -4134,6 +4283,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 de3a904695a..5ca9f525f39 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,
 
 	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;
@@ -3678,6 +3679,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 41415986e64..a8b9518a415 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] 62+ messages in thread

* Re: [PATCH v3 03/28] Add new classes that model DWARF stack element
  2021-10-14  9:32 ` [PATCH v3 03/28] Add new classes that model DWARF stack element Zoran Zaric
@ 2021-10-21 23:43   ` Lancelot SIX
  2021-10-22 16:38     ` Zoran Zaric
  0 siblings, 1 reply; 62+ messages in thread
From: Lancelot SIX @ 2021-10-21 23:43 UTC (permalink / raw)
  To: Zoran Zaric; +Cc: gdb-patches

Hi,

I have some remarks/comments/questions I have included in the patch.

I am far from having reached the end of your series.  I am not entirely
sure if I should send comments as I progress or go through all of it and
send all my comments at once when I have reached the end (which can take
a while).  Is there a way you prefer?

Best,
Lancelot.

> ---
>  gdb/dwarf2/expr.c | 234 ++++++++++++++++++++++++++++++++++++++++++++++
>  gdb/value.c       |   2 +-
>  gdb/value.h       |   2 +
>  3 files changed, 237 insertions(+), 1 deletion(-)
> 
> diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
> index c0ca78ce236..f44dfd1b260 100644
> --- a/gdb/dwarf2/expr.c
> +++ b/gdb/dwarf2/expr.c
> @@ -271,6 +271,240 @@ 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
> +{
> +public:
> +  /* Not expected to be called on it's own.  */
> +  dwarf_entry () = default;

If this constructor is not meant to be called directly, I guest it could
be possible to make it protected.  This way it can no longer be used by
a user of the class while still be usable by the child of this class.

> +
> +  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
> +{
> +public:
> +  /* Not expected to be called on it's own.  */
> +  dwarf_location (gdbarch *arch, LONGEST offset)
> +    : m_arch (arch), m_offset (offset)
> +  {}

Same remark on the visibility of the constructor here (based on the same
comment).

> +
> +  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 : public dwarf_entry

It does not look like dwarf_value has child classes. It could be
declared final as you have done for dwarf_undefined for example.

> +{
> +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_unsigned_long (m_contents.data (), type, value);

Shouldn't it be pack_long instead here?

> +  }
> +
> +  gdb::array_view<const gdb_byte> contents () const
> +  {
> +    return m_contents;
> +  }
> +
> +  struct type* type () const

Minor remark first so I do not forget: I think GDB coding style prefers
'type *' over 'type* ' (space before the '*', no space after).

Unless there is a reason not to, I would be tempted to return a pointer
to const (i.e. const struct type *) in order to maintain the const
correctness here.

One way out could be to have two versions of the type method:

  struct type *type ();
  const struct type *type () const;

I have tested this on top of the entire series, it seems to be OK.

> +  {
> +    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 bb2adae0a51..0623d29a595 100644
> --- a/gdb/value.c
> +++ b/gdb/value.c
> @@ -3465,7 +3465,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 45012372dbf..a01dc8de9f7 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] 62+ messages in thread

* Re: [PATCH v3 03/28] Add new classes that model DWARF stack element
  2021-10-21 23:43   ` Lancelot SIX
@ 2021-10-22 16:38     ` Zoran Zaric
  2021-10-22 21:34       ` Lancelot SIX
  0 siblings, 1 reply; 62+ messages in thread
From: Zoran Zaric @ 2021-10-22 16:38 UTC (permalink / raw)
  To: Lancelot SIX; +Cc: gdb-patches

Hi Lancelot,

Thank you for reviewing my patches. I know that they are a bit big.

> I am far from having reached the end of your series.  I am not entirely
> sure if I should send comments as I progress or go through all of it and
> send all my comments at once when I have reached the end (which can take
> a while).  Is there a way you prefer?
> 
> Best,
> Lancelot.

Maybe it is better to do it as you progress because that way I can fix 
things in the same order on my side.

I will also let some time period to pass before I send the updated 
series, to give people time to comment on the current one.

>> +class dwarf_entry
>> +{
>> +public:
>> +  /* Not expected to be called on it's own.  */
>> +  dwarf_entry () = default;
> 
> If this constructor is not meant to be called directly, I guest it could
> be possible to make it protected.  This way it can no longer be used by
> a user of the class while still be usable by the child of this class.
> 

Good point.

>> +
>> +  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
>> +{
>> +public:
>> +  /* Not expected to be called on it's own.  */
>> +  dwarf_location (gdbarch *arch, LONGEST offset)
>> +    : m_arch (arch), m_offset (offset)
>> +  {}
> 
> Same remark on the visibility of the constructor here (based on the same
> comment).
> 

Agreed.

>> +
>> +  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 : public dwarf_entry
> 
> It does not look like dwarf_value has child classes. It could be
> declared final as you have done for dwarf_undefined for example.

Agreed.

> 
>> +{
>> +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_unsigned_long (m_contents.data (), type, value);
> 
> Shouldn't it be pack_long instead here?

It should, and it was in one of the previous patches. Copy paste mistake 
from my last iteration I guess.

> 
>> +  }
>> +
>> +  gdb::array_view<const gdb_byte> contents () const
>> +  {
>> +    return m_contents;
>> +  }
>> +
>> +  struct type* type () const
> 
> Minor remark first so I do not forget: I think GDB coding style prefers
> 'type *' over 'type* ' (space before the '*', no space after).

No matter how many times I go through these patches, I will still miss 
something...

Thanks :)

> 
> Unless there is a reason not to, I would be tempted to return a pointer
> to const (i.e. const struct type *) in order to maintain the const
> correctness here.
> 
> One way out could be to have two versions of the type method:
> 
>    struct type *type ();
>    const struct type *type () const;
> 
> I have tested this on top of the entire series, it seems to be OK. >

I am fine with this change as long as there is no existing API that 
prevents me to use the const type *, and it seems that you already 
checked for that.

I will make sure to fix everything in the next iteration.

Zoran

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

* Re: [PATCH v3 04/28] Add to_location method to DWARF entry classes
  2021-10-14  9:32 ` [PATCH v3 04/28] Add to_location method to DWARF entry classes Zoran Zaric
@ 2021-10-22 21:21   ` Lancelot SIX
  2021-10-25 21:23     ` Simon Marchi
  2021-11-01 16:00     ` Zoran Zaric
  0 siblings, 2 replies; 62+ messages in thread
From: Lancelot SIX @ 2021-10-22 21:21 UTC (permalink / raw)
  To: Zoran Zaric; +Cc: gdb-patches

Hi,

As for the previous patch, I have included comments and questions
below.

On Thu, Oct 14, 2021 at 10:32:11AM +0100, Zoran Zaric via Gdb-patches wrote:
> 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 entry classes need to have a support for those.
> 
> This patch adds a conversion method from any DWARF entry object into a
> location description object.

Reading this, I kind of expect to find the 'to_location' method to be
defined in dwarf_entry, but it is only created for dwarf_value (the only
non-dwarf_location-based class).

Reading a bit ahead, I looks like the to_location free function that will
be introduced in patch 16 of this series ('Change DWARF stack to use new
dwarf_entry classes') could fit the description.  After having a look at
this function, it looks like it could have been included in this patch
instead.  Was it intended be be included here and somehow slipped in
another patch?

> 
> gdb/ChangeLog:
> 
>         * dwarf2/expr.c (class dwarf_value::to_location): New method.
> ---
>  gdb/dwarf2/expr.c | 36 ++++++++++++++++++++++++++++++++++++
>  1 file changed, 36 insertions(+)
> 
> diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
> index f44dfd1b260..5d443edfd9d 100644
> --- a/gdb/dwarf2/expr.c
> +++ b/gdb/dwarf2/expr.c
> @@ -36,6 +36,16 @@
>  #include "inferior.h"
>  #include "observable.h"
>  
> +/* Stolen from libstdc++ and adjusted, so probably fine license-wise.
> +   Could be added in gdbsupport.  */
> +
> +template<typename _Tp, typename ... _Args>
> +std::unique_ptr<_Tp>
> +make_unique (_Args &&... __args)
> +{
> +  return std::unique_ptr<_Tp> (new _Tp (std::forward<_Args>(__args)...));
> +}

I would be tempted to use the implementation from the standard library
when available (i.e. if compiling in c++14 and later).  Something like
that should do it:

	#if __cplusplus >= 201402L
	#include <memory>
	
	using std::make_unique;
	#else
	/* template<...> std::unique_ptr<T> make_unique(...){}  */
	#endif

This is quite similar to what is done in gdbsupport/gdb_string_view.h.

And to follow what is done in the string_view example, make_unique could
probably be declared in the gdb namespace.  I guess this suggestion
would mainly make sense if this code is moved to gdbsupport (as
suggested in the comment).

One possible limitation of placing this in gdbsupport is that this
implementation does not handle the 'template<class T> std::unique_ptr<T>
std::make_unique (std::size_t size)' case used to create arrays.
It would be easy to borrow it from libstdc++ as well if we wanted to
have a fully compliant make_unique implementation.

Maybe a maintainer has an opinion on the whether this should be moved to
gdbsupport?

> +
>  /* Cookie for gdbarch data.  */
>  
>  static struct gdbarch_data *dwarf_arch_cookie;
> @@ -271,6 +281,9 @@ write_to_memory (CORE_ADDR address, const gdb_byte *buffer,
>  					 length, buffer);
>  }
>  
> +class dwarf_location;
> +class dwarf_memory;

As far as I can see, there is no need of a forward declaration of
dwarf_memory.

Best,
Lancelot.

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

* Re: [PATCH v3 03/28] Add new classes that model DWARF stack element
  2021-10-22 16:38     ` Zoran Zaric
@ 2021-10-22 21:34       ` Lancelot SIX
  0 siblings, 0 replies; 62+ messages in thread
From: Lancelot SIX @ 2021-10-22 21:34 UTC (permalink / raw)
  To: Zoran Zaric; +Cc: gdb-patches

On Fri, Oct 22, 2021 at 05:38:13PM +0100, Zoran Zaric via Gdb-patches wrote:
> Hi Lancelot,
> 
> Thank you for reviewing my patches. I know that they are a bit big.

Hi

No worries.  I’ll eventually reach the end!  And for the moment I find
the series well organized and easy to follow even if it involves a part
of the codebase I am not faniliar with.

> 
> No matter how many times I go through these patches, I will still miss
> something...

Haha, I know the feeling!

> 
> Thanks :)
> 
> > 
> > Unless there is a reason not to, I would be tempted to return a pointer
> > to const (i.e. const struct type *) in order to maintain the const
> > correctness here.
> > 
> > One way out could be to have two versions of the type method:
> > 
> >    struct type *type ();
> >    const struct type *type () const;
> > 
> > I have tested this on top of the entire series, it seems to be OK. >
> 
> I am fine with this change as long as there is no existing API that prevents
> me to use the const type *, and it seems that you already checked for that.

Only using the 'const struct type *type () const' variant breaks a lot
of things as many function dealing with type expect a 'struct type*'
argument.  I had a quick look to see how deep the changes would have to
be and realized that having a non const version was a way simpler
solution.

Lancelot.

> 
> I will make sure to fix everything in the next iteration.
> 
> Zoran

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

* Re: [PATCH v3 06/28] Add read method to location description classes
  2021-10-14  9:32 ` [PATCH v3 06/28] Add read method to location description classes Zoran Zaric
@ 2021-10-25 18:33   ` Lancelot SIX
  2021-10-25 21:37     ` Simon Marchi
  0 siblings, 1 reply; 62+ messages in thread
From: Lancelot SIX @ 2021-10-25 18:33 UTC (permalink / raw)
  To: Zoran Zaric; +Cc: gdb-patches

Hi,

On Thu, Oct 14, 2021 at 10:32:13AM +0100, Zoran Zaric via Gdb-patches wrote:
> 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 56f17f52756..3f3e09db7cc 100644
> --- a/gdb/dwarf2/expr.c
> +++ b/gdb/dwarf2/expr.c
> @@ -289,6 +289,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.

There is an extra '.' at the end of this line.

> +   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] == NULL)

It is not a big deal, but I think nullptr is preferred over NULL for
new/updated code (there are few across the series, I can point them out
if you want).

> +    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_memory;
>  class dwarf_value;
> @@ -349,6 +379,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;
> @@ -426,6 +477,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
> @@ -442,6 +501,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;
> @@ -468,6 +532,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;

I am not entirely sure of what follows, so if a maintainer can step in,
I would appreciate.

I am not sure HOST_CHAR_BIT is what should be used here.  This is meant
to compute an address on the target.  The number of bits per byte might
(in theory) be different on the host and the target.  From what I
understand, this is where gdbarch_addressable_memory_unit_size could
come into play (it gives the number of octets associated with a memory
address for the given arch).

In practice however, I do not know what target has non 8-bit bytes.
set_gdbarch_addressable_memory_unit_size seems to never be called in the
codebase, so I guess if such target has gdb support, it is off-tree.

As I said before, I am not entirely sure to what extent such target
are currently supported.  Is this something you have considered?

Best,
Lancelot.

> +  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
> @@ -477,11 +581,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 == NULL)
> +    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.  */
> @@ -497,6 +646,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;
> @@ -505,6 +658,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
> @@ -520,6 +712,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;
> @@ -534,6 +730,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) + 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
> @@ -549,6 +783,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.  */
> @@ -570,6 +808,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.  */
> @@ -1185,27 +1467,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] 62+ messages in thread

* Re: [PATCH v3 07/28] Add write method to location description classes
  2021-10-14  9:32 ` [PATCH v3 07/28] Add write " Zoran Zaric
@ 2021-10-25 20:21   ` Lancelot SIX
  2021-11-03 10:27     ` Zoran Zaric
  0 siblings, 1 reply; 62+ messages in thread
From: Lancelot SIX @ 2021-10-25 20:21 UTC (permalink / raw)
  To: Zoran Zaric; +Cc: gdb-patches

On Thu, Oct 14, 2021 at 10:32:14AM +0100, Zoran Zaric via Gdb-patches wrote:
> 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 opeque implementation of the computed struct value

Hi,

Probably a small typo here.

opeque -> opaque ?

Best,
Lancelot.

> 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 3f3e09db7cc..83a2db028ca 100644
> --- a/gdb/dwarf2/expr.c
> +++ b/gdb/dwarf2/expr.c
> @@ -400,6 +400,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;
> @@ -485,6 +507,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
> @@ -506,6 +536,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;
> @@ -572,6 +607,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;
> +
> +  total_bits_to_skip += m_bit_suboffset;
> +  *optimized = 0;
> +
> +  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
> @@ -585,6 +676,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;
> @@ -631,6 +727,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 == NULL)
> +    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.  */
> @@ -650,6 +793,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;
> @@ -716,6 +868,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;
> @@ -787,6 +948,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.  */
> @@ -852,6 +1018,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] 62+ messages in thread

* Re: [PATCH v3 04/28] Add to_location method to DWARF entry classes
  2021-10-22 21:21   ` Lancelot SIX
@ 2021-10-25 21:23     ` Simon Marchi
  2021-11-01 16:01       ` Zoran Zaric
  2021-11-01 16:00     ` Zoran Zaric
  1 sibling, 1 reply; 62+ messages in thread
From: Simon Marchi @ 2021-10-25 21:23 UTC (permalink / raw)
  To: Lancelot SIX, Zoran Zaric; +Cc: gdb-patches

> I would be tempted to use the implementation from the standard library
> when available (i.e. if compiling in c++14 and later).  Something like
> that should do it:
> 
> 	#if __cplusplus >= 201402L
> 	#include <memory>
> 	
> 	using std::make_unique;
> 	#else
> 	/* template<...> std::unique_ptr<T> make_unique(...){}  */
> 	#endif
> 
> This is quite similar to what is done in gdbsupport/gdb_string_view.h.
> 
> And to follow what is done in the string_view example, make_unique could
> probably be declared in the gdb namespace.  I guess this suggestion
> would mainly make sense if this code is moved to gdbsupport (as
> suggested in the comment).
> 
> One possible limitation of placing this in gdbsupport is that this
> implementation does not handle the 'template<class T> std::unique_ptr<T>
> std::make_unique (std::size_t size)' case used to create arrays.
> It would be easy to borrow it from libstdc++ as well if we wanted to
> have a fully compliant make_unique implementation.
> 
> Maybe a maintainer has an opinion on the whether this should be moved to
> gdbsupport?

I think it would be good to have a gdb::make_unique in gdbsupport, as
you described (that uses the one from the standard library if
__cplusplus >= 201402L).  There are surely other spots that could
benefit from it.

Simon

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

* Re: [PATCH v3 06/28] Add read method to location description classes
  2021-10-25 18:33   ` Lancelot SIX
@ 2021-10-25 21:37     ` Simon Marchi
  2021-11-02 14:26       ` Zoran Zaric
  0 siblings, 1 reply; 62+ messages in thread
From: Simon Marchi @ 2021-10-25 21:37 UTC (permalink / raw)
  To: Lancelot SIX, Zoran Zaric; +Cc: gdb-patches



On 2021-10-25 14:33, Lancelot SIX via Gdb-patches wrote:
> Hi,
> 
> On Thu, Oct 14, 2021 at 10:32:13AM +0100, Zoran Zaric via Gdb-patches wrote:
>> 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 56f17f52756..3f3e09db7cc 100644
>> --- a/gdb/dwarf2/expr.c
>> +++ b/gdb/dwarf2/expr.c
>> @@ -289,6 +289,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.
> 
> There is an extra '.' at the end of this line.
> 
>> +   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] == NULL)
> 
> It is not a big deal, but I think nullptr is preferred over NULL for
> new/updated code (there are few across the series, I can point them out
> if you want).
> 
>> +    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_memory;
>>  class dwarf_value;
>> @@ -349,6 +379,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;
>> @@ -426,6 +477,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
>> @@ -442,6 +501,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;
>> @@ -468,6 +532,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;
> 
> I am not entirely sure of what follows, so if a maintainer can step in,
> I would appreciate.
> 
> I am not sure HOST_CHAR_BIT is what should be used here.  This is meant
> to compute an address on the target.  The number of bits per byte might
> (in theory) be different on the host and the target.  From what I
> understand, this is where gdbarch_addressable_memory_unit_size could
> come into play (it gives the number of octets associated with a memory
> address for the given arch).
> 
> In practice however, I do not know what target has non 8-bit bytes.
> set_gdbarch_addressable_memory_unit_size seems to never be called in the
> codebase, so I guess if such target has gdb support, it is off-tree.
> 
> As I said before, I am not entirely sure to what extent such target
> are currently supported.  Is this something you have considered?

It's true that there isn't an architecture upstream which uses that
feature.  I was the one who introduced
gdbarch_addressable_memory_unit_size, while at my previous job, because
we had a platform with non-8-bit-bytes.  And this was merged, as it was
seen as an improvement over using TARGET_CHAR_BIT (TARGET_CHAR_BIT is a
compile-time constant, so if you are building a GDB that debugs
architectures with different byte sizes... that doesn't work).

So yeah, gdbarch_addressable_memory_unit_size looks like the right thing
to use here.  Note that this function returns 1 for x86, and 2 for an
architecture with 16-bit bytes.  So you would divide by:

  gdbarch_addressable_memory_unit_size (arch) * 8

I am fine with using the magical number 8 here, because
gdbarch_addressable_memory_unit_size is explicitly defined as "the size
in 8-bit bytes of...".  Using CHAR_BIT or something like that would
defeat the purpose because it could *in theory* be something else than
8.

So cases like this one, we do a best effort to write things in a way
that works for non-8-bit-bytes platform, but don't sweat it too much.
Users downstream who actually use that will fix it and provide patches
if needed.

Simon

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

* Re: [PATCH v3 08/28] Add deref method to location description classes
  2021-10-14  9:32 ` [PATCH v3 08/28] Add deref " Zoran Zaric
@ 2021-10-25 22:31   ` Lancelot SIX
  2021-11-03 10:51     ` Zoran Zaric
  0 siblings, 1 reply; 62+ messages in thread
From: Lancelot SIX @ 2021-10-25 22:31 UTC (permalink / raw)
  To: Zoran Zaric; +Cc: gdb-patches

Hi,

I include few comments in the patch bellow.

On Thu, Oct 14, 2021 at 10:32:15AM +0100, Zoran Zaric via Gdb-patches wrote:
> 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 an universal method that model the

*a* universal method that *models*

> 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 | 121 ++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 121 insertions(+)
> 
> diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
> index 83a2db028ca..87caba5fd62 100644
> --- a/gdb/dwarf2/expr.c
> +++ b/gdb/dwarf2/expr.c
> @@ -422,6 +422,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 then the TYPE type size.

then -> than ?

> +     If SIZE is smaller then the type size, the value will be zero

then -> than ?

> +     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;
> @@ -489,6 +501,43 @@ class dwarf_value : 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 do read-modify-write to "
> +		   "update bitfield; containing word "
> +		   "has been optimized out"));

The error message should be about dereferencing I guess.

> +  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.  */
> @@ -541,6 +590,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;
> @@ -663,6 +717,73 @@ 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;
> +      /* Using second buffer here because the copy_bitwise
> +	 doesn't support in place copy.  */
> +      gdb::byte_vector temp_buf (this_size);

I guess the temp_buf can be declared in the if bellow. If
addr_info->valaddr does not contain the data we are looking for, there
is no need to create a unused buffer on the stack.

> +
> +      if (offset < addr_info->valaddr.size ()
> +	  && offset + this_size <= addr_info->valaddr.size ())
> +	{
> +	  memcpy (temp_buf.data (), addr_info->valaddr.data (), this_size);

Isn't it addr_info->valaddr.data() + offset ?

> +	  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 do read-modify-write to "
> +		     "update bitfield; containing word "
> +		     "has been optimized out"));

The message should also be about dereferencing I guess.

Best,
Lancelot.

> +      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] 62+ messages in thread

* Re: [PATCH v3 12/28] Add indirect_implicit_ptr to dwarf_location class
  2021-10-14  9:32 ` [PATCH v3 12/28] Add indirect_implicit_ptr to dwarf_location class Zoran Zaric
@ 2021-10-26 20:52   ` Lancelot SIX
  2021-11-03 15:11     ` Zoran Zaric
  0 siblings, 1 reply; 62+ messages in thread
From: Lancelot SIX @ 2021-10-26 20:52 UTC (permalink / raw)
  To: Zoran Zaric; +Cc: gdb-patches

Hi,

I have included very minor comments in the patch.

On Thu, Oct 14, 2021 at 10:32:19AM +0100, Zoran Zaric via Gdb-patches wrote:
> 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 then reading from a struct value object (previously

then -> than

> 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 then the deref method

then -> than

> 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 aa36a992e09..af84710b054 100644
> --- a/gdb/dwarf2/expr.c
> +++ b/gdb/dwarf2/expr.c
> @@ -474,6 +474,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
                 ^^
Two spaces after the '.' here.

Best,
Lancelot.

> +     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;
> @@ -1103,6 +1121,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;
> @@ -1155,6 +1178,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
> @@ -1191,6 +1225,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.  */
> @@ -1424,6 +1463,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] 62+ messages in thread

* Re: [PATCH v3 14/28] Add new computed struct value callback interface
  2021-10-14  9:32 ` [PATCH v3 14/28] Add new computed struct value callback interface Zoran Zaric
@ 2021-10-26 22:50   ` Lancelot SIX
  2021-11-04 11:32     ` Zoran Zaric
  0 siblings, 1 reply; 62+ messages in thread
From: Lancelot SIX @ 2021-10-26 22:50 UTC (permalink / raw)
  To: Zoran Zaric; +Cc: gdb-patches

Hi,

As for previous patches, I have included (minor) comments below.

On Thu, Oct 14, 2021 at 10:32:21AM +0100, Zoran Zaric via Gdb-patches wrote:
> 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 | 307 ++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 307 insertions(+)
> 
> diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
> index 1b6622d5f59..e33be7e7c1c 100644
> --- a/gdb/dwarf2/expr.c
> +++ b/gdb/dwarf2/expr.c
> @@ -323,6 +323,92 @@ class dwarf_location;
>  class dwarf_memory;
>  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;

Is there a reason not to inline this function definition as well?  It
seems as trivial as get_frame_id and get_frame.

> +
> +  frame_id get_frame_id () const
> +  {

If I understand correctly, m_frame_id and m_frame are mutually
exclusive.  To be on the safe side, I would be tempted to add a check
here:

	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 = NULL;

I guess nullptr is prefered over NULL (across the patch).

> +};
> +
>  /* Base class that describes entries found on a DWARF expression
>     evaluation stack.  */
>  
> @@ -524,6 +610,11 @@ class dwarf_location : public dwarf_entry
>  
>  using dwarf_location_up = std::unique_ptr<dwarf_location>;
>  
> +const dwarf_location &computed_closure::get_location () const
> +{
> +  return *m_location;
> +}
> +
>  void
>  dwarf_location::read_from_gdb_value (frame_info *frame, struct value *value,
>  				     int value_bit_offset,
> @@ -1594,6 +1685,222 @@ 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);
> +  bool big_endian = type_byte_order (value_type (v)) == BFD_ENDIAN_BIG;
> +  const dwarf_location &location = closure->get_location ();
> +
> +  if (from == NULL)
> +    {
> +      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"));
> +    }
> +
> +  ULONGEST bits_to_skip = HOST_CHAR_BIT * 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 * value_offset (value_parent (v))
> +		       + value_bitpos (v);
> +      if (from != NULL && 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 (value_type (v));
> +
> +  frame_info *frame = closure->get_frame ();
> +
> +  if (frame == NULL)
> +    frame = frame_find_by_id (closure->get_frame_id ());
> +
> +  if (from == NULL)
> +    {
> +      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 contains describes any piece

One of 'contains' and 'describes' might be too much here I guess.

Best,
Lancelot.

> +   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);
> +  bool big_endian = type_byte_order (value_type (v)) == BFD_ENDIAN_BIG;
> +  const dwarf_location &location = closure->get_location ();
> +
> +  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"));
> +
> +  ULONGEST bits_to_skip = HOST_CHAR_BIT * 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 * value_offset (value_parent (v))
> +		      + value_bitpos (v);
> +      max_bit_size = value_bitsize (v);
> +    }
> +  else
> +    max_bit_size = HOST_CHAR_BIT * TYPE_LENGTH (value_type (v));
> +
> +  frame_info *frame = closure->get_frame ();
> +
> +  if (frame == NULL)
> +    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)
> +{
> +  LONGEST total_bit_offset = bit_offset + HOST_CHAR_BIT * value_offset (value);
> +
> +  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 NULL;
> +
> +  LONGEST bit_length = HOST_CHAR_BIT * TYPE_LENGTH (type);
> +  LONGEST bit_offset = HOST_CHAR_BIT * 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),
> +			      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),
> +				    TARGET_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 NULL;
> +    }
> +}
> +
>  struct piece_closure
>  {
>    /* Reference count.  */
> -- 
> 2.17.1
> 

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

* Re: [PATCH v3 16/28] Change DWARF stack to use new dwarf_entry classes
  2021-10-14  9:32 ` [PATCH v3 16/28] Change DWARF stack to use new dwarf_entry classes Zoran Zaric
@ 2021-10-31 17:58   ` Lancelot SIX
  2021-11-04 12:43     ` Zoran Zaric
  0 siblings, 1 reply; 62+ messages in thread
From: Lancelot SIX @ 2021-10-31 17:58 UTC (permalink / raw)
  To: Zoran Zaric; +Cc: gdb-patches

Hi,

I have included below minor remarks, mostly about wording of comments
(so, really, nothing serious).

Best,
Lancelot.

On Thu, Oct 14, 2021 at 10:32:23AM +0100, Zoran Zaric via Gdb-patches wrote:
> 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                             | 1364 ++++++++---------
>  gdb/dwarf2/expr.h                             |   91 +-
>  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, 701 insertions(+), 760 deletions(-)
> 
> diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
> index a34a5037686..8c116cc60b6 100644
> --- a/gdb/dwarf2/expr.c
> +++ b/gdb/dwarf2/expr.c
> @@ -409,20 +409,6 @@ class computed_closure : public refcounted_object
>    frame_info *m_frame = NULL;
>  };
>  
> -/* Base class that describes entries found on a DWARF expression
> -   evaluation stack.  */
> -
> -class dwarf_entry
> -{
> -public:
> -  /* Not expected to be called on it's own.  */
> -  dwarf_entry () = default;
> -
> -  virtual ~dwarf_entry () = default;
> -};
> -
> -using dwarf_entry_up = std::unique_ptr<dwarf_entry>;
> -
>  /* Location description entry found on a DWARF expression evaluation
>     stack.
>  
> @@ -441,6 +427,11 @@ class dwarf_location : public dwarf_entry
>  
>    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;
> @@ -704,6 +695,11 @@ class dwarf_value : 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 +1961,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 a given DWARF value arguments.

Maybe use 'on dwarf_value arguments.' (otherwise the 'a' and 'arguments'
seems strange to me).

> +
> +   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 lesser then DWARF value ARG2 in a

is lesser then -> is less than

> +   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)
>  {
> @@ -2181,6 +2289,53 @@ 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);
> +
> +  LONGEST offset = value_offset (value);
> +
> +  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) + 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.  */
> @@ -2200,34 +2355,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
> @@ -2809,43 +2936,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.  */
> @@ -2889,7 +3020,6 @@ dwarf_expr_context::get_base_type (cu_offset die_cu_off)
>  
>    if (result == nullptr)
>      error (_("Could not find type for operation"));
> -
>    return result;
>  }
>  
> @@ -2920,31 +3050,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,
> @@ -2997,7 +3102,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)
> @@ -3006,148 +3110,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),
> -		    value_contents_all (val) + 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);
> -	    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.  */
> @@ -3222,103 +3195,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),
> -				     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
> @@ -3365,7 +3303,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
> @@ -3585,9 +3522,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);
> @@ -3596,17 +3530,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.  */
> @@ -3646,92 +3569,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.  */
> @@ -3767,21 +3729,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:
>  	  {
> @@ -3790,19 +3754,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:
> @@ -3813,20 +3786,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:
> @@ -3860,78 +3835,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:
>  	  {
> @@ -3940,15 +3927,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:
> @@ -3958,13 +3943,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:
> @@ -3973,72 +3956,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:
> @@ -4059,189 +4033,216 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr,
>  	case DW_OP_ne:
>  	  {
>  	    /* Binary operations.  */
> -	    struct value *first, *second;
> -
> -	    second = fetch (0);
> -	    pop ();
> +	    dwarf_value_up arg2 = to_value (pop (), address_type);
> +	    dwarf_value_up arg1 = to_value (pop (), address_type);
>  
> -	    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

return returns -> return

> +	       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:
>  	  {
> @@ -4249,16 +4250,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:
>  	  {
> @@ -4268,23 +4262,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:
>  	  {
> @@ -4292,8 +4287,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:
>  	  {
> @@ -4301,8 +4296,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:
>  	  {
> @@ -4310,15 +4305,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:
> @@ -4338,7 +4341,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,
> @@ -4351,7 +4354,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 "
> @@ -4369,111 +4372,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));
> +	      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..aaae381f4fe 100644
> --- a/gdb/dwarf2/expr.h
> +++ b/gdb/dwarf2/expr.h
> @@ -25,6 +25,22 @@
>  #include "leb128.h"
>  #include "gdbtypes.h"
>  
> +/* Base class that describes entries found on a DWARF expression
> +   evaluation stack.  */
> +
> +class dwarf_entry
> +{
> +public:
> +  /* Not expected to be called on it's own.  */
> +  dwarf_entry () = default;

This was mentioned in a earlier patch but I re-state it here because it
is easy to miss it when reabasing since this part is temporarily moved
from another file: this ctor could be turned protected.

> +
> +  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 +114,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 +123,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 +144,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 +155,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 +169,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 +207,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 8b81b5b2119..c6505e09bc5 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] 62+ messages in thread

* Re: [PATCH v3 23/28] Add support for any location description in CFI
  2021-10-14  9:32 ` [PATCH v3 23/28] Add support for any location description in CFI Zoran Zaric
@ 2021-10-31 22:58   ` Lancelot SIX
  2021-11-04 15:09     ` Zoran Zaric
  0 siblings, 1 reply; 62+ messages in thread
From: Lancelot SIX @ 2021-10-31 22:58 UTC (permalink / raw)
  To: Zoran Zaric; +Cc: gdb-patches

Hi,

I have included minor nits below

On Thu, Oct 14, 2021 at 10:32:30AM +0100, Zoran Zaric via Gdb-patches wrote:
> 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        | 36 +++++++++++++++++++++++++------
>  2 files changed, 61 insertions(+), 29 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 16673258373..3d85d2c7b59 100644
> --- a/gdb/frame.c
> +++ b/gdb/frame.c
> @@ -1532,26 +1532,50 @@ 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))
> +
> +      /*  Compute value is a special new case.  The problem is that
           ^^
There is one extra space at the start of the comment (and in the
subsequent lines I guess).

Also the comment related to a 'new case'.  From the perspective of
someone reading the comment in frame.c (not in a patch), this just like
a special case.  Maybe rephrase with something like:

	Computed value is a special case.  The computed callback
	mechanism requires a strut value argument, so we need to make
	one.

> +	  the computed callback mechanism only supports a struct
> +	  value arguments, so we need to make one.  */
> +      if (value != NULL && VALUE_LVAL (value) == lval_computed)

Prefer nullptr over NULL.

> +	{
> +	  const lval_funcs *funcs = value_computed_funcs (value);
> +	  type * reg_type = register_type (gdbarch, regnum);

I guess funcs->write could be checked to be non nullptr before
retrieving regtype.  If 'error' is called, reg_type has no use.

> +
> +	  if (funcs->write == NULL)

NULL -> nullptr

> +	    error (_("Attempt to assign to an unmodifiable value."));
> +
> +	  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);
>  
> -	  memcpy ((char *) value_contents_writeable (value) + offset, myaddr,
> -		  curr_len);
> +	  memcpy ((char *) value_contents_writeable (value) + offset,
> +		  myaddr, curr_len);
>  	  put_frame_register (frame, regnum, value_contents_raw (value));
> -	  release_value (value);
>  	}
>  
> +      if (value != NULL)

NULL -> nullptr

Best,
Lancelot.


> +	release_value (value);
> +
>        myaddr += curr_len;
>        len -= curr_len;
>        offset = 0;
> -- 
> 2.17.1
> 

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

* Re: [PATCH v3 04/28] Add to_location method to DWARF entry classes
  2021-10-22 21:21   ` Lancelot SIX
  2021-10-25 21:23     ` Simon Marchi
@ 2021-11-01 16:00     ` Zoran Zaric
  2021-11-01 17:48       ` Lancelot SIX
  1 sibling, 1 reply; 62+ messages in thread
From: Zoran Zaric @ 2021-11-01 16:00 UTC (permalink / raw)
  To: Lancelot SIX; +Cc: gdb-patches

Thank you for reviewing my patch.

On 10/22/21 10:21 PM, Lancelot SIX wrote:
> [CAUTION: External Email]
> 
> Hi,
> 
> As for the previous patch, I have included comments and questions
> below.
> 
> On Thu, Oct 14, 2021 at 10:32:11AM +0100, Zoran Zaric via Gdb-patches wrote:
>> 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 entry classes need to have a support for those.
>>
>> This patch adds a conversion method from any DWARF entry object into a
>> location description object.
> 
> Reading this, I kind of expect to find the 'to_location' method to be
> defined in dwarf_entry, but it is only created for dwarf_value (the only
> non-dwarf_location-based class).
> 
> Reading a bit ahead, I looks like the to_location free function that will
> be introduced in patch 16 of this series ('Change DWARF stack to use new
> dwarf_entry classes') could fit the description.  After having a look at
> this function, it looks like it could have been included in this patch
> instead.  Was it intended be be included here and somehow slipped in
> another patch?

I will change the patch notes to say the the method was added to 
dwarf_value class and leave the description of the free function to the 
patch where I actually add it.

I can't really add the free function at this point in the series because 
it is still not used anywhere and the gdb build system will complain.

Zoran


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

* Re: [PATCH v3 04/28] Add to_location method to DWARF entry classes
  2021-10-25 21:23     ` Simon Marchi
@ 2021-11-01 16:01       ` Zoran Zaric
  2021-11-01 20:36         ` Simon Marchi
  0 siblings, 1 reply; 62+ messages in thread
From: Zoran Zaric @ 2021-11-01 16:01 UTC (permalink / raw)
  To: Simon Marchi, Lancelot SIX; +Cc: gdb-patches



On 10/25/21 10:23 PM, Simon Marchi wrote:
> [CAUTION: External Email]
> 
>> I would be tempted to use the implementation from the standard library
>> when available (i.e. if compiling in c++14 and later).  Something like
>> that should do it:
>>
>>        #if __cplusplus >= 201402L
>>        #include <memory>
>>
>>        using std::make_unique;
>>        #else
>>        /* template<...> std::unique_ptr<T> make_unique(...){}  */
>>        #endif
>>
>> This is quite similar to what is done in gdbsupport/gdb_string_view.h.
>>
>> And to follow what is done in the string_view example, make_unique could
>> probably be declared in the gdb namespace.  I guess this suggestion
>> would mainly make sense if this code is moved to gdbsupport (as
>> suggested in the comment).
>>
>> One possible limitation of placing this in gdbsupport is that this
>> implementation does not handle the 'template<class T> std::unique_ptr<T>
>> std::make_unique (std::size_t size)' case used to create arrays.
>> It would be easy to borrow it from libstdc++ as well if we wanted to
>> have a fully compliant make_unique implementation.
>>
>> Maybe a maintainer has an opinion on the whether this should be moved to
>> gdbsupport?
> 
> I think it would be good to have a gdb::make_unique in gdbsupport, as
> you described (that uses the one from the standard library if
> __cplusplus >= 201402L).  There are surely other spots that could
> benefit from it.
> 
> Simon
> 

Makes sense.

Should I just add the existing function in this patch and leave the 
array version for someone to add it later?

I don't like adding utility functions which are not currently in use.

Zoran

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

* Re: [PATCH v3 04/28] Add to_location method to DWARF entry classes
  2021-11-01 16:00     ` Zoran Zaric
@ 2021-11-01 17:48       ` Lancelot SIX
  0 siblings, 0 replies; 62+ messages in thread
From: Lancelot SIX @ 2021-11-01 17:48 UTC (permalink / raw)
  To: Zoran Zaric; +Cc: gdb-patches

On Mon, Nov 01, 2021 at 04:00:02PM +0000, Zoran Zaric via Gdb-patches wrote:
> Thank you for reviewing my patch.
> 
> On 10/22/21 10:21 PM, Lancelot SIX wrote:
> > [CAUTION: External Email]
> > 
> > Hi,
> > 
> > As for the previous patch, I have included comments and questions
> > below.
> > 
> > On Thu, Oct 14, 2021 at 10:32:11AM +0100, Zoran Zaric via Gdb-patches wrote:
> > > 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 entry classes need to have a support for those.
> > > 
> > > This patch adds a conversion method from any DWARF entry object into a
> > > location description object.
> > 
> > Reading this, I kind of expect to find the 'to_location' method to be
> > defined in dwarf_entry, but it is only created for dwarf_value (the only
> > non-dwarf_location-based class).
> > 
> > Reading a bit ahead, I looks like the to_location free function that will
> > be introduced in patch 16 of this series ('Change DWARF stack to use new
> > dwarf_entry classes') could fit the description.  After having a look at
> > this function, it looks like it could have been included in this patch
> > instead.  Was it intended be be included here and somehow slipped in
> > another patch?
> 
> I will change the patch notes to say the the method was added to dwarf_value
> class and leave the description of the free function to the patch where I
> actually add it.
> 
> I can't really add the free function at this point in the series because it
> is still not used anywhere and the gdb build system will complain.

Indeed, that makes sense. 

Thanks for the explanation!

Lancelot.

> 
> Zoran
> 

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

* Re: [PATCH v3 04/28] Add to_location method to DWARF entry classes
  2021-11-01 16:01       ` Zoran Zaric
@ 2021-11-01 20:36         ` Simon Marchi
  0 siblings, 0 replies; 62+ messages in thread
From: Simon Marchi @ 2021-11-01 20:36 UTC (permalink / raw)
  To: Zoran Zaric, Lancelot SIX; +Cc: gdb-patches

On 2021-11-01 12:01 p.m., Zoran Zaric wrote:
>
>
> On 10/25/21 10:23 PM, Simon Marchi wrote:
>> [CAUTION: External Email]
>>
>>> I would be tempted to use the implementation from the standard library
>>> when available (i.e. if compiling in c++14 and later).  Something like
>>> that should do it:
>>>
>>>        #if __cplusplus >= 201402L
>>>        #include <memory>
>>>
>>>        using std::make_unique;
>>>        #else
>>>        /* template<...> std::unique_ptr<T> make_unique(...){}  */
>>>        #endif
>>>
>>> This is quite similar to what is done in gdbsupport/gdb_string_view.h.
>>>
>>> And to follow what is done in the string_view example, make_unique could
>>> probably be declared in the gdb namespace.  I guess this suggestion
>>> would mainly make sense if this code is moved to gdbsupport (as
>>> suggested in the comment).
>>>
>>> One possible limitation of placing this in gdbsupport is that this
>>> implementation does not handle the 'template<class T> std::unique_ptr<T>
>>> std::make_unique (std::size_t size)' case used to create arrays.
>>> It would be easy to borrow it from libstdc++ as well if we wanted to
>>> have a fully compliant make_unique implementation.
>>>
>>> Maybe a maintainer has an opinion on the whether this should be moved to
>>> gdbsupport?
>>
>> I think it would be good to have a gdb::make_unique in gdbsupport, as
>> you described (that uses the one from the standard library if
>> __cplusplus >= 201402L).  There are surely other spots that could
>> benefit from it.
>>
>> Simon
>>
>
> Makes sense.
>
> Should I just add the existing function in this patch and leave the array version for someone to add it later?
>
> I don't like adding utility functions which are not currently in use.
>
> Zoran

What's the array version?  Do you mean prototype (2) on [1]?

    template< class T >
    unique_ptr<T> make_unique( std::size_t size );

If so, my answer is: just add what you need.  If somebody needs the
array version, they can add it (unless we already have a use for it in
the code base and you feel like adding it, then go ahead).

Simon

[1] https://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique

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

* Re: [PATCH v3 27/28] Add DW_OP_LLVM_extend DWARF operation
  2021-10-14  9:32 ` [PATCH v3 27/28] Add DW_OP_LLVM_extend DWARF operation Zoran Zaric
@ 2021-11-01 21:48   ` Lancelot SIX
  2021-11-04 16:26     ` Zoran Zaric
  0 siblings, 1 reply; 62+ messages in thread
From: Lancelot SIX @ 2021-11-01 21:48 UTC (permalink / raw)
  To: Zoran Zaric; +Cc: gdb-patches

Hi,

On Thu, Oct 14, 2021 at 10:32:34AM +0100, Zoran Zaric via Gdb-patches wrote:
> 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                  |   4 +
>  gdb/dwarf2/expr.c                            |  44 ++++++
>  gdb/dwarf2/loc.c                             |  12 ++
>  gdb/testsuite/gdb.dwarf2/dw2-llvm-extend.exp | 148 +++++++++++++++++++
>  gdb/testsuite/lib/dwarf.exp                  |   5 +
>  include/dwarf2.def                           |   1 +
>  6 files changed, 214 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..2c5e13cfb6c 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_extend:
> +	  stack_depth -= 2;

If DW_OP_LLVM_extend pops one element from the stack and pushes one
composite value back, shouldn't the net result be 0i stack_depth wise?

Best,
Lancelot.

> +	  break;
> +
>  	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 3cf4c78e4dc..711a5918946 100644
> --- a/gdb/dwarf2/expr.c
> +++ b/gdb/dwarf2/expr.c
> @@ -2498,6 +2498,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);
> @@ -2860,6 +2869,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)
>  {
> @@ -4090,6 +4123,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 c93981e9721..de3a904695a 100644
> --- a/gdb/dwarf2/loc.c
> +++ b/gdb/dwarf2/loc.c
> @@ -1953,6 +1953,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;
> @@ -3666,6 +3667,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..2a82eed02b8
> --- /dev/null
> +++ b/gdb/testsuite/gdb.dwarf2/dw2-llvm-extend.exp
> @@ -0,0 +1,148 @@
> +# 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_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 ac943cb0419..41415986e64 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] 62+ messages in thread

* Re: [PATCH v3 28/28] Add DW_OP_LLVM_select_bit_piece DWARF operation
  2021-10-14  9:32 ` [PATCH v3 28/28] Add DW_OP_LLVM_select_bit_piece " Zoran Zaric
@ 2021-11-01 22:25   ` Lancelot SIX
  2021-11-04 16:39     ` Zoran Zaric
  0 siblings, 1 reply; 62+ messages in thread
From: Lancelot SIX @ 2021-11-01 22:25 UTC (permalink / raw)
  To: Zoran Zaric; +Cc: gdb-patches

Hi,

I have included remarks below.

On Thu, Oct 14, 2021 at 10:32:35AM +0100, Zoran Zaric via Gdb-patches wrote:
> 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                   |   1 +
>  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, 317 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 2c5e13cfb6c..5991760adbc 100644
> --- a/gdb/compile/compile-loc2c.c
> +++ b/gdb/compile/compile-loc2c.c
> @@ -367,6 +367,7 @@ compute_stack_depth_worker (int start, int *need_tempvar,
>  	  break;
>  
>  	case DW_OP_LLVM_extend:
> +	case DW_OP_LLVM_select_bit_piece:
>  	  stack_depth -= 2;
>  	  break;
>  
> diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
> index 711a5918946..874a5d1923b 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.
> @@ -621,6 +630,17 @@ const dwarf_location &computed_closure::get_location () const
>    return *m_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,
> @@ -1567,6 +1587,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);
> @@ -1653,6 +1676,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,
> @@ -2507,6 +2588,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);
> @@ -2893,6 +2988,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)
>  {
> @@ -4134,6 +4283,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 de3a904695a..5ca9f525f39 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,
>  
>  	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;
> @@ -3678,6 +3679,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.

Based on a comment in the following thread:
https://sourceware.org/pipermail/gdb-patches/2021-September/182104.html,
I guess that this second line of copyright should be removed.

I did not spot in the earlier patch, but it looks that the same line
remains in gdb.dwarf2/dw2-llvm-extend.exp as well.

> +
> +# 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]

Looks like you have spaces instead of tabs to indent this line.

Best,
Lancelot.

> +			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 41415986e64..a8b9518a415 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] 62+ messages in thread

* Re: [PATCH v3 06/28] Add read method to location description classes
  2021-10-25 21:37     ` Simon Marchi
@ 2021-11-02 14:26       ` Zoran Zaric
  2021-11-03 19:03         ` Simon Marchi
  0 siblings, 1 reply; 62+ messages in thread
From: Zoran Zaric @ 2021-11-02 14:26 UTC (permalink / raw)
  To: Simon Marchi, Lancelot SIX; +Cc: gdb-patches


>>
>> I am not entirely sure of what follows, so if a maintainer can step in,
>> I would appreciate.
>>
>> I am not sure HOST_CHAR_BIT is what should be used here.  This is meant
>> to compute an address on the target.  The number of bits per byte might
>> (in theory) be different on the host and the target.  From what I
>> understand, this is where gdbarch_addressable_memory_unit_size could
>> come into play (it gives the number of octets associated with a memory
>> address for the given arch).
>>
>> In practice however, I do not know what target has non 8-bit bytes.
>> set_gdbarch_addressable_memory_unit_size seems to never be called in the
>> codebase, so I guess if such target has gdb support, it is off-tree.
>>
>> As I said before, I am not entirely sure to what extent such target
>> are currently supported.  Is this something you have considered?
> 
> It's true that there isn't an architecture upstream which uses that
> feature.  I was the one who introduced
> gdbarch_addressable_memory_unit_size, while at my previous job, because
> we had a platform with non-8-bit-bytes.  And this was merged, as it was
> seen as an improvement over using TARGET_CHAR_BIT (TARGET_CHAR_BIT is a
> compile-time constant, so if you are building a GDB that debugs
> architectures with different byte sizes... that doesn't work).
> 
> So yeah, gdbarch_addressable_memory_unit_size looks like the right thing
> to use here.  Note that this function returns 1 for x86, and 2 for an
> architecture with 16-bit bytes.  So you would divide by:
> 
>    gdbarch_addressable_memory_unit_size (arch) * 8
> 
> I am fine with using the magical number 8 here, because
> gdbarch_addressable_memory_unit_size is explicitly defined as "the size
> in 8-bit bytes of...".  Using CHAR_BIT or something like that would
> defeat the purpose because it could *in theory* be something else than
> 8.
> 
> So cases like this one, we do a best effort to write things in a way
> that works for non-8-bit-bytes platform, but don't sweat it too much.
> Users downstream who actually use that will fix it and provide patches
> if needed.
> 
> Simon
> 

The problem that I have with this idea is that DWARF doesn't speak in
terms of addressable memory units, but in terms of byte representation 
of an architecture.

The addressable memory units only describe what an underlying memory 
read write interface need to consider, but from a location description 
point of view we need a byte/bit correlation that describes all location 
description kinds uniformly and the addressable memory units is not it.

For example, how would this work in the case of registers? In most 
architectures they are only addressable as a whole.

Another problem here is that the m_offset is not equivalent to offset
or embedded offset from struct value. This is especially true for memory 
location descriptions where the m_offset member is an offset from the 
beginning of the memory location as a whole aka the address itself.

Previously the only way to add an offset to a memory location is to 
implicitly convert it to the value on the expression stack, add an 
offset to it and then convert it back to an address. This means that if 
the expression yielded unaddressable address, the read would just fail 
and the gdb would not try to compensate by reading more then copy with 
an offset.

Considering all of this, the only correct thing to do here is either use 
hard coded value of 8 (like was done before my changes) or use the 
TARGET_BYTE_CHAR instead until there is a need for a proper byte/bit 
correlation target hook.

I can also see that we are using gdbarch_addressable_memory_unit_size
call for some struct value API (for example value_contents_copy) for 
offset and embedded offset regardless of the location description kind.

This is obviously wrong, but it was not detected from the DWARF side 
because the only way how one can add an offset to a register location is 
through the lval_computed interface which goes around these issues.

Because now this is not the case, I can solve this issue by making sure 
that when a dwarf_entry class is converted to a struct value object, the 
struct value offset member (and the corresponding bit offset member) are 
still talking about offset in terms of addressable units for all 
locations description kinds.

Zoran




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

* Re: [PATCH v3 07/28] Add write method to location description classes
  2021-10-25 20:21   ` Lancelot SIX
@ 2021-11-03 10:27     ` Zoran Zaric
  0 siblings, 0 replies; 62+ messages in thread
From: Zoran Zaric @ 2021-11-03 10:27 UTC (permalink / raw)
  To: Lancelot SIX; +Cc: gdb-patches



On 10/25/21 9:21 PM, Lancelot SIX wrote:
> [CAUTION: External Email]
> 
> On Thu, Oct 14, 2021 at 10:32:14AM +0100, Zoran Zaric via Gdb-patches wrote:
>> 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 opeque implementation of the computed struct value
> 
> Hi,
> 
> Probably a small typo here.
> 
> opeque -> opaque ?
> 
> Best,
> Lancelot.
> 

Thank you,
Zoran

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

* Re: [PATCH v3 08/28] Add deref method to location description classes
  2021-10-25 22:31   ` Lancelot SIX
@ 2021-11-03 10:51     ` Zoran Zaric
  2021-11-03 17:37       ` Simon Marchi
  0 siblings, 1 reply; 62+ messages in thread
From: Zoran Zaric @ 2021-11-03 10:51 UTC (permalink / raw)
  To: Lancelot SIX; +Cc: gdb-patches

>>
>> 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 an universal method that model the
> 
> *a* universal method that *models*

Are you sure about this?

English is not my first language, but isn't it a rule to put (an) 
instead of (a) if the next word starts with a vowel?

>>
>> +  /* 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 then the TYPE type size.
> 
> then -> than ?
> 
>> +     If SIZE is smaller then the type size, the value will be zero
> 
> then -> than ?

Thank you.

>> +
>> +  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 do read-modify-write to "
>> +                "update bitfield; containing word "
>> +                "has been optimized out"));
> 
> The error message should be about dereferencing I guess.

Thank you.

>> +  /* 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;
>> +      /* Using second buffer here because the copy_bitwise
>> +      doesn't support in place copy.  */
>> +      gdb::byte_vector temp_buf (this_size);
> 
> I guess the temp_buf can be declared in the if bellow. If
> addr_info->valaddr does not contain the data we are looking for, there
> is no need to create a unused buffer on the stack.
> 

True. Thank you.

>> +
>> +      if (offset < addr_info->valaddr.size ()
>> +       && offset + this_size <= addr_info->valaddr.size ())
>> +     {
>> +       memcpy (temp_buf.data (), addr_info->valaddr.data (), this_size);
> 
> Isn't it addr_info->valaddr.data() + offset ?
> 

Good find,

I guess none of the existing Ada tests are using the passed in buffer 
with an offset in the expression.

Thanks.

>> +
>> +      if (optimized)
>> +     throw_error (OPTIMIZED_OUT_ERROR,
>> +                  _("Can't do read-modify-write to "
>> +                  "update bitfield; containing word "
>> +                  "has been optimized out"));
> 
> The message should also be about dereferencing I guess.
> 
> Best,
> Lancelot.

Thank you,
Zoran

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

* Re: [PATCH v3 12/28] Add indirect_implicit_ptr to dwarf_location class
  2021-10-26 20:52   ` Lancelot SIX
@ 2021-11-03 15:11     ` Zoran Zaric
  0 siblings, 0 replies; 62+ messages in thread
From: Zoran Zaric @ 2021-11-03 15:11 UTC (permalink / raw)
  To: Lancelot SIX; +Cc: gdb-patches


>>
>> 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 then reading from a struct value object (previously
> 
> then -> than
> 
>> 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 then the deref method
> 
> then -> than
> 
>>
>> +  /* 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
>                   ^^
> Two spaces after the '.' here.
> 
> Best,
> Lancelot.
> 

All good points. Thank you.

Zoran

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

* Re: [PATCH v3 08/28] Add deref method to location description classes
  2021-11-03 10:51     ` Zoran Zaric
@ 2021-11-03 17:37       ` Simon Marchi
  2021-11-05 11:55         ` Zoran Zaric
  0 siblings, 1 reply; 62+ messages in thread
From: Simon Marchi @ 2021-11-03 17:37 UTC (permalink / raw)
  To: Zoran Zaric, Lancelot SIX; +Cc: gdb-patches

On 2021-11-03 6:51 a.m., Zoran Zaric via Gdb-patches wrote:
>>>
>>> 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 an universal method that model the
>>
>> *a* universal method that *models*
> 
> Are you sure about this?
> 
> English is not my first language, but isn't it a rule to put (an) instead of (a) if the next word starts with a vowel?

See:

https://www.writersdigest.com/write-better-fiction/a-before-consonants-and-an-before-vowels-is-not-the-rule

Simon

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

* Re: [PATCH v3 06/28] Add read method to location description classes
  2021-11-02 14:26       ` Zoran Zaric
@ 2021-11-03 19:03         ` Simon Marchi
  2021-11-05 11:58           ` Zoran Zaric
  0 siblings, 1 reply; 62+ messages in thread
From: Simon Marchi @ 2021-11-03 19:03 UTC (permalink / raw)
  To: Zoran Zaric, Lancelot SIX; +Cc: gdb-patches

> The problem that I have with this idea is that DWARF doesn't speak in
> terms of addressable memory units, but in terms of byte representation of an architecture.
>
> The addressable memory units only describe what an underlying memory read write interface need to consider, but from a location description point of view we need a byte/bit correlation that describes all location description kinds uniformly and the addressable memory units is not it.
>
> For example, how would this work in the case of registers? In most architectures they are only addressable as a whole.
>
> Another problem here is that the m_offset is not equivalent to offset
> or embedded offset from struct value. This is especially true for memory location descriptions where the m_offset member is an offset from the beginning of the memory location as a whole aka the address itself.
>
> Previously the only way to add an offset to a memory location is to implicitly convert it to the value on the expression stack, add an offset to it and then convert it back to an address. This means that if the expression yielded unaddressable address, the read would just fail and the gdb would not try to compensate by reading more then copy with an offset.
>
> Considering all of this, the only correct thing to do here is either use hard coded value of 8 (like was done before my changes) or use the TARGET_BYTE_CHAR instead until there is a need for a proper byte/bit correlation target hook.
>
> I can also see that we are using gdbarch_addressable_memory_unit_size
> call for some struct value API (for example value_contents_copy) for offset and embedded offset regardless of the location description kind.
>
> This is obviously wrong, but it was not detected from the DWARF side because the only way how one can add an offset to a register location is through the lval_computed interface which goes around these issues.
>
> Because now this is not the case, I can solve this issue by making sure that when a dwarf_entry class is converted to a struct value object, the struct value offset member (and the corresponding bit offset member) are still talking about offset in terms of addressable units for all locations description kinds.

I spoke with Zoran offline about this.  In the end, the conclusion is
that there are too many unknowns on how things are expected to work with
non-8-bit-bytes targets.  On one hand, the DWARF standard makes it
sound (section 1.3.2 of DWARF 5) like a "byte" can be other sizes than 8
bits:

    DWARF can be used with a wide range of processor architectures, whether byte
    or word oriented, linear or segmented, with any word or byte size.

So when you apply an offset measured in bytes in a location, that would
be using the target processor byte size.  And that would apply to all
locations, registers, memory and others (especially since you want to
treat all locations kinds the same).

But as you have mentioned, all areas of GDB are not consistent regarding
this.  Some code paths today use an hard-coded 8 when applying offsets.
I think this is more related to the fact that when we upstreamed these
bits (in my previous life), we changed whatever code paths our GDB was
taking, not all.

Since there isn't even one architecture upstream using non-8-bit-bytes,
you can't even take a peek to see how it works.  So I would say, do
whatever is the easiest for you (except using TARGET_CHAR_BIT :)).  If
that's assuming 8-bit offsets everywhere, go for it.  If it's using
gdbarch_addressable_memory_unit_size-sized offsets for all location
kinds, go for it.  This means the behavior of GDB for non-8-bit-bytes
target can change, but IMO that's ok.  The current code is likely not
entirely correct as is anyway.  And if somebody downstream is still
using GDB for such a target, they'll have to contribute fixes if they
want to.  We can't guess what's right.  And if nobody is using such a
target downstream, then it doesn't change anything.

Simon

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

* Re: [PATCH v3 14/28] Add new computed struct value callback interface
  2021-10-26 22:50   ` Lancelot SIX
@ 2021-11-04 11:32     ` Zoran Zaric
  0 siblings, 0 replies; 62+ messages in thread
From: Zoran Zaric @ 2021-11-04 11:32 UTC (permalink / raw)
  To: Lancelot SIX; +Cc: gdb-patches


>> +
>> +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;
> 
> Is there a reason not to inline this function definition as well?  It
> seems as trivial as get_frame_id and get_frame.
> 

There was a reason in one of the previous versions, but not anymore.

Thank you.

>> +
>> +  frame_id get_frame_id () const
>> +  {
> 
> If I understand correctly, m_frame_id and m_frame are mutually
> exclusive.  To be on the safe side, I would be tempted to add a check
> here:
> 
>          gdb_assert (m_frame == nullptr);
> 

I didn't want to force them to be mutual exclusive, but when I think 
about it more it makes sense to make them. Thanks.

>> +    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 = NULL;
> 
> I guess nullptr is prefered over NULL (across the patch).
> 

Thanks. I will do another pass on those.

>> +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 contains describes any piece
> 
> One of 'contains' and 'describes' might be too much here I guess.
> 
> Best,
> Lancelot.

Thank you,
Zoran

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

* Re: [PATCH v3 16/28] Change DWARF stack to use new dwarf_entry classes
  2021-10-31 17:58   ` Lancelot SIX
@ 2021-11-04 12:43     ` Zoran Zaric
  0 siblings, 0 replies; 62+ messages in thread
From: Zoran Zaric @ 2021-11-04 12:43 UTC (permalink / raw)
  To: Lancelot SIX; +Cc: gdb-patches


>> +
>> +  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 a given DWARF value arguments.
> 
> Maybe use 'on dwarf_value arguments.' (otherwise the 'a' and 'arguments'
> seems strange to me).
> 

I see what you mean. Thanks.

>> +
>> +   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 lesser then DWARF value ARG2 in a
> 
> is lesser then -> is less than
> 

The funny thing is that this was there in the original code and nobody
noticed until now. Thanks.


>> diff --git a/gdb/dwarf2/expr.h b/gdb/dwarf2/expr.h
>> index 16c5e710ff5..aaae381f4fe 100644
>> --- a/gdb/dwarf2/expr.h
>> +++ b/gdb/dwarf2/expr.h
>> @@ -25,6 +25,22 @@
>>   #include "leb128.h"
>>   #include "gdbtypes.h"
>>
>> +/* Base class that describes entries found on a DWARF expression
>> +   evaluation stack.  */
>> +
>> +class dwarf_entry
>> +{
>> +public:
>> +  /* Not expected to be called on it's own.  */
>> +  dwarf_entry () = default;
> 
> This was mentioned in a earlier patch but I re-state it here because it
> is easy to miss it when reabasing since this part is temporarily moved
> from another file: this ctor could be turned protected.
> 

Thank you for tracking it through the series for me :).

Like discussed on some previous patches (PATCH v3 6/28) comment threads, 
I will also add a comment at the beginning of the expr.c file in this 
patch to explain that the evaluator is using the HOST_CHAR_SIZE constant
instead the hard coded number 8 until there is a proper support for 
different sizes bytes.

I was advised to use this constant by a maintainer Pedro Alves, because 
the value of that constant is apparently always guaranteed to be 8.

Much appreciate it,
Zoran

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

* Re: [PATCH v3 23/28] Add support for any location description in CFI
  2021-10-31 22:58   ` Lancelot SIX
@ 2021-11-04 15:09     ` Zoran Zaric
  0 siblings, 0 replies; 62+ messages in thread
From: Zoran Zaric @ 2021-11-04 15:09 UTC (permalink / raw)
  To: Lancelot SIX; +Cc: gdb-patches



On 10/31/21 10:58 PM, Lancelot SIX wrote:
> [CAUTION: External Email]
> 
> Hi,
> 
> I have included minor nits below
> 
> On Thu, Oct 14, 2021 at 10:32:30AM +0100, Zoran Zaric via Gdb-patches wrote:
>> 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        | 36 +++++++++++++++++++++++++------
>>   2 files changed, 61 insertions(+), 29 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);
>>   }
>>
>>
>> @@ -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 16673258373..3d85d2c7b59 100644
>> --- a/gdb/frame.c
>> +++ b/gdb/frame.c
>> @@ -1532,26 +1532,50 @@ 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))
>> +
>> +      /*  Compute value is a special new case.  The problem is that
>             ^^
> There is one extra space at the start of the comment (and in the
> subsequent lines I guess).
> 
> Also the comment related to a 'new case'.  From the perspective of
> someone reading the comment in frame.c (not in a patch), this just like
> a special case.  Maybe rephrase with something like:
> 
>          Computed value is a special case.  The computed callback
>          mechanism requires a strut value argument, so we need to make
>          one.
> 
>> +       the computed callback mechanism only supports a struct
>> +       value arguments, so we need to make one.  */
>> +      if (value != NULL && VALUE_LVAL (value) == lval_computed)
> 
> Prefer nullptr over NULL.
> 
>> +     {
>> +       const lval_funcs *funcs = value_computed_funcs (value);
>> +       type * reg_type = register_type (gdbarch, regnum);
> 
> I guess funcs->write could be checked to be non nullptr before
> retrieving regtype.  If 'error' is called, reg_type has no use.
> 
>> +
>> +       if (funcs->write == NULL)
> 
> NULL -> nullptr
> 
>> +         error (_("Attempt to assign to an unmodifiable value."));
>> +
>> +       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);
>>
>> -       memcpy ((char *) value_contents_writeable (value) + offset, myaddr,
>> -               curr_len);
>> +       memcpy ((char *) value_contents_writeable (value) + offset,
>> +               myaddr, curr_len);
>>          put_frame_register (frame, regnum, value_contents_raw (value));
>> -       release_value (value);
>>        }
>>
>> +      if (value != NULL)
> 
> NULL -> nullptr
> 
> Best,
> Lancelot.
> 

All valid points.

Thank you,
Zoran

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

* Re: [PATCH v3 27/28] Add DW_OP_LLVM_extend DWARF operation
  2021-11-01 21:48   ` Lancelot SIX
@ 2021-11-04 16:26     ` Zoran Zaric
  0 siblings, 0 replies; 62+ messages in thread
From: Zoran Zaric @ 2021-11-04 16:26 UTC (permalink / raw)
  To: Lancelot SIX; +Cc: gdb-patches



On 11/1/21 9:48 PM, Lancelot SIX wrote:
> [CAUTION: External Email]
> 
> Hi,
> 
> On Thu, Oct 14, 2021 at 10:32:34AM +0100, Zoran Zaric via Gdb-patches wrote:
>> 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                  |   4 +
>>   gdb/dwarf2/expr.c                            |  44 ++++++
>>   gdb/dwarf2/loc.c                             |  12 ++
>>   gdb/testsuite/gdb.dwarf2/dw2-llvm-extend.exp | 148 +++++++++++++++++++
>>   gdb/testsuite/lib/dwarf.exp                  |   5 +
>>   include/dwarf2.def                           |   1 +
>>   6 files changed, 214 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..2c5e13cfb6c 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_extend:
>> +       stack_depth -= 2;
> 
> If DW_OP_LLVM_extend pops one element from the stack and pushes one
> composite value back, shouldn't the net result be 0i stack_depth wise?
> 
> Best,
> Lancelot.
> 

Good point.

Thanks,
Zoran

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

* Re: [PATCH v3 28/28] Add DW_OP_LLVM_select_bit_piece DWARF operation
  2021-11-01 22:25   ` Lancelot SIX
@ 2021-11-04 16:39     ` Zoran Zaric
  0 siblings, 0 replies; 62+ messages in thread
From: Zoran Zaric @ 2021-11-04 16:39 UTC (permalink / raw)
  To: Lancelot SIX; +Cc: gdb-patches


>> @@ -0,0 +1,138 @@
>> +# Copyright (C) 2017-2021 Free Software Foundation, Inc.
>> +# Copyright (C) 2020-2021 Advanced Micro Devices, Inc. All rights reserved.
> 
> Based on a comment in the following thread:
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fsourceware.org%2Fpipermail%2Fgdb-patches%2F2021-September%2F182104.html&amp;data=04%7C01%7Czoran.zaric%40amd.com%7Ca666d2f8c5c546ff3d4808d99d86755b%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637714023668693445%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;sdata=5JvJg6uxGFRzFLCRBaxVV14fKzWvIlOFTs7YeJp0bT8%3D&amp;reserved=0,
> I guess that this second line of copyright should be removed.
> 
> I did not spot in the earlier patch, but it looks that the same line
> remains in gdb.dwarf2/dw2-llvm-extend.exp as well.
> 

Thank you, I will fix both in the next version.

>> +         } {
>> +
>> +             # 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]
> 
> Looks like you have spaces instead of tabs to indent this line.
> 
> Best,
> Lancelot.
> 

Thank you,
Zoran

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

* Re: [PATCH v3 00/28] Allow location description on the DWARF stack
  2021-10-14  9:32 [PATCH v3 00/28] Allow location description on the DWARF stack Zoran Zaric
                   ` (27 preceding siblings ...)
  2021-10-14  9:32 ` [PATCH v3 28/28] Add DW_OP_LLVM_select_bit_piece " Zoran Zaric
@ 2021-11-05 11:54 ` Zaric, Zoran (Zare)
  28 siblings, 0 replies; 62+ messages in thread
From: Zaric, Zoran (Zare) @ 2021-11-05 11:54 UTC (permalink / raw)
  To: gdb-patches

[AMD Official Use Only]

A new version of this patch series has been sent.

Thanks to everybody that reviewed the previous version,
Zoran
________________________________
From: Zaric, Zoran (Zare) <Zoran.Zaric@amd.com>
Sent: 14 October 2021 10:32
To: gdb-patches@sourceware.org <gdb-patches@sourceware.org>
Cc: Zaric, Zoran (Zare) <Zoran.Zaric@amd.com>
Subject: [PATCH v3 00/28] Allow location description on the DWARF stack

Based on gdb master: f19c3684a6db145f57048bff5485fec6e3dd0f76

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 entry classes
  Add to_value method to DWARF entry classes
  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                             | 4229 ++++++++++++-----
 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                                   |   48 +-
 gdb/testsuite/gdb.dwarf2/dw2-llvm-extend.exp  |  148 +
 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                                  |  129 +-
 gdb/value.c                                   |   68 +-
 gdb/value.h                                   |    4 +-
 include/dwarf2.def                            |    8 +
 22 files changed, 4381 insertions(+), 1505 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] 62+ messages in thread

* Re: [PATCH v3 08/28] Add deref method to location description classes
  2021-11-03 17:37       ` Simon Marchi
@ 2021-11-05 11:55         ` Zoran Zaric
  0 siblings, 0 replies; 62+ messages in thread
From: Zoran Zaric @ 2021-11-05 11:55 UTC (permalink / raw)
  To: Simon Marchi, Lancelot SIX; +Cc: gdb-patches



On 11/3/21 5:37 PM, Simon Marchi wrote:
> [CAUTION: External Email]
> 
> On 2021-11-03 6:51 a.m., Zoran Zaric via Gdb-patches wrote:
>>>>
>>>> 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 an universal method that model the
>>>
>>> *a* universal method that *models*
>>
>> Are you sure about this?
>>
>> English is not my first language, but isn't it a rule to put (an) instead of (a) if the next word starts with a vowel?
> 
> See:
> 
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.writersdigest.com%2Fwrite-better-fiction%2Fa-before-consonants-and-an-before-vowels-is-not-the-rule&amp;data=04%7C01%7Czoran.zaric%40amd.com%7C44a4378493c14871978408d99ef09636%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637715578577013403%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&amp;sdata=3jrt5GPxYmCoxQ54fbMNgPaOLzncczjW2EEnWpMV1f4%3D&amp;reserved=0
> 
> Simon
> 

My bad then,
Zoran

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

* Re: [PATCH v3 06/28] Add read method to location description classes
  2021-11-03 19:03         ` Simon Marchi
@ 2021-11-05 11:58           ` Zoran Zaric
  0 siblings, 0 replies; 62+ messages in thread
From: Zoran Zaric @ 2021-11-05 11:58 UTC (permalink / raw)
  To: Simon Marchi, Lancelot SIX; +Cc: gdb-patches



On 11/3/21 7:03 PM, Simon Marchi wrote:
> [CAUTION: External Email]
> 
>> The problem that I have with this idea is that DWARF doesn't speak in
>> terms of addressable memory units, but in terms of byte representation of an architecture.
>>
>> The addressable memory units only describe what an underlying memory read write interface need to consider, but from a location description point of view we need a byte/bit correlation that describes all location description kinds uniformly and the addressable memory units is not it.
>>
>> For example, how would this work in the case of registers? In most architectures they are only addressable as a whole.
>>
>> Another problem here is that the m_offset is not equivalent to offset
>> or embedded offset from struct value. This is especially true for memory location descriptions where the m_offset member is an offset from the beginning of the memory location as a whole aka the address itself.
>>
>> Previously the only way to add an offset to a memory location is to implicitly convert it to the value on the expression stack, add an offset to it and then convert it back to an address. This means that if the expression yielded unaddressable address, the read would just fail and the gdb would not try to compensate by reading more then copy with an offset.
>>
>> Considering all of this, the only correct thing to do here is either use hard coded value of 8 (like was done before my changes) or use the TARGET_BYTE_CHAR instead until there is a need for a proper byte/bit correlation target hook.
>>
>> I can also see that we are using gdbarch_addressable_memory_unit_size
>> call for some struct value API (for example value_contents_copy) for offset and embedded offset regardless of the location description kind.
>>
>> This is obviously wrong, but it was not detected from the DWARF side because the only way how one can add an offset to a register location is through the lval_computed interface which goes around these issues.
>>
>> Because now this is not the case, I can solve this issue by making sure that when a dwarf_entry class is converted to a struct value object, the struct value offset member (and the corresponding bit offset member) are still talking about offset in terms of addressable units for all locations description kinds.
> 
> I spoke with Zoran offline about this.  In the end, the conclusion is
> that there are too many unknowns on how things are expected to work with
> non-8-bit-bytes targets.  On one hand, the DWARF standard makes it
> sound (section 1.3.2 of DWARF 5) like a "byte" can be other sizes than 8
> bits:
> 
>      DWARF can be used with a wide range of processor architectures, whether byte
>      or word oriented, linear or segmented, with any word or byte size.
> 
> So when you apply an offset measured in bytes in a location, that would
> be using the target processor byte size.  And that would apply to all
> locations, registers, memory and others (especially since you want to
> treat all locations kinds the same).
> 
> But as you have mentioned, all areas of GDB are not consistent regarding
> this.  Some code paths today use an hard-coded 8 when applying offsets.
> I think this is more related to the fact that when we upstreamed these
> bits (in my previous life), we changed whatever code paths our GDB was
> taking, not all.
> 
> Since there isn't even one architecture upstream using non-8-bit-bytes,
> you can't even take a peek to see how it works.  So I would say, do
> whatever is the easiest for you (except using TARGET_CHAR_BIT :)).  If
> that's assuming 8-bit offsets everywhere, go for it.  If it's using
> gdbarch_addressable_memory_unit_size-sized offsets for all location
> kinds, go for it.  This means the behavior of GDB for non-8-bit-bytes
> target can change, but IMO that's ok.  The current code is likely not
> entirely correct as is anyway.  And if somebody downstream is still
> using GDB for such a target, they'll have to contribute fixes if they
> want to.  We can't guess what's right.  And if nobody is using such a
> target downstream, then it doesn't change anything.
> 
> Simon
> 

I agree with this. Also, the reason why I use the HOST_CHAR_SIZE is 
because Pedro Alves suggested for me to use it instead of the hard coded 
number 8 because apparently, that constant is always guaranteed to have 
a value 8.

Thanks for all the reviews guys. I've just uploaded a new series with 
all the fixes.

Zoran

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

end of thread, other threads:[~2021-11-05 11:58 UTC | newest]

Thread overview: 62+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-10-14  9:32 [PATCH v3 00/28] Allow location description on the DWARF stack Zoran Zaric
2021-10-14  9:32 ` [PATCH v3 01/28] Add new register access interface to expr.c Zoran Zaric
2021-10-14  9:32 ` [PATCH v3 02/28] Add new memory " Zoran Zaric
2021-10-14  9:32 ` [PATCH v3 03/28] Add new classes that model DWARF stack element Zoran Zaric
2021-10-21 23:43   ` Lancelot SIX
2021-10-22 16:38     ` Zoran Zaric
2021-10-22 21:34       ` Lancelot SIX
2021-10-14  9:32 ` [PATCH v3 04/28] Add to_location method to DWARF entry classes Zoran Zaric
2021-10-22 21:21   ` Lancelot SIX
2021-10-25 21:23     ` Simon Marchi
2021-11-01 16:01       ` Zoran Zaric
2021-11-01 20:36         ` Simon Marchi
2021-11-01 16:00     ` Zoran Zaric
2021-11-01 17:48       ` Lancelot SIX
2021-10-14  9:32 ` [PATCH v3 05/28] Add to_value " Zoran Zaric
2021-10-14  9:32 ` [PATCH v3 06/28] Add read method to location description classes Zoran Zaric
2021-10-25 18:33   ` Lancelot SIX
2021-10-25 21:37     ` Simon Marchi
2021-11-02 14:26       ` Zoran Zaric
2021-11-03 19:03         ` Simon Marchi
2021-11-05 11:58           ` Zoran Zaric
2021-10-14  9:32 ` [PATCH v3 07/28] Add write " Zoran Zaric
2021-10-25 20:21   ` Lancelot SIX
2021-11-03 10:27     ` Zoran Zaric
2021-10-14  9:32 ` [PATCH v3 08/28] Add deref " Zoran Zaric
2021-10-25 22:31   ` Lancelot SIX
2021-11-03 10:51     ` Zoran Zaric
2021-11-03 17:37       ` Simon Marchi
2021-11-05 11:55         ` Zoran Zaric
2021-10-14  9:32 ` [PATCH v3 09/28] Add read_from_gdb_value method to dwarf_location Zoran Zaric
2021-10-14  9:32 ` [PATCH v3 10/28] Add write_to_gdb_value " Zoran Zaric
2021-10-14  9:32 ` [PATCH v3 11/28] Add is_implicit_ptr_at " Zoran Zaric
2021-10-14  9:32 ` [PATCH v3 12/28] Add indirect_implicit_ptr to dwarf_location class Zoran Zaric
2021-10-26 20:52   ` Lancelot SIX
2021-11-03 15:11     ` Zoran Zaric
2021-10-14  9:32 ` [PATCH v3 13/28] Add is_optimized_out " Zoran Zaric
2021-10-14  9:32 ` [PATCH v3 14/28] Add new computed struct value callback interface Zoran Zaric
2021-10-26 22:50   ` Lancelot SIX
2021-11-04 11:32     ` Zoran Zaric
2021-10-14  9:32 ` [PATCH v3 15/28] Add to_gdb_value method to DWARF entry class Zoran Zaric
2021-10-14  9:32 ` [PATCH v3 16/28] Change DWARF stack to use new dwarf_entry classes Zoran Zaric
2021-10-31 17:58   ` Lancelot SIX
2021-11-04 12:43     ` Zoran Zaric
2021-10-14  9:32 ` [PATCH v3 17/28] Remove old computed struct value callbacks Zoran Zaric
2021-10-14  9:32 ` [PATCH v3 18/28] Comments cleanup between expr.h and expr.c Zoran Zaric
2021-10-14  9:32 ` [PATCH v3 19/28] Remove dwarf_expr_context from expr.h interface Zoran Zaric
2021-10-14  9:32 ` [PATCH v3 20/28] Move read_addr_from_reg function to frame.c Zoran Zaric
2021-10-14  9:32 ` [PATCH v3 21/28] Add frame info check to DW_OP_reg operations Zoran Zaric
2021-10-14  9:32 ` [PATCH v3 22/28] Remove DWARF expression composition check Zoran Zaric
2021-10-14  9:32 ` [PATCH v3 23/28] Add support for any location description in CFI Zoran Zaric
2021-10-31 22:58   ` Lancelot SIX
2021-11-04 15:09     ` Zoran Zaric
2021-10-14  9:32 ` [PATCH v3 24/28] Add DWARF operations for byte and bit offset Zoran Zaric
2021-10-14  9:32 ` [PATCH v3 25/28] Add support for DW_OP_LLVM_undefined operation Zoran Zaric
2021-10-14  9:32 ` [PATCH v3 26/28] Add support for nested composite locations Zoran Zaric
2021-10-14  9:32 ` [PATCH v3 27/28] Add DW_OP_LLVM_extend DWARF operation Zoran Zaric
2021-11-01 21:48   ` Lancelot SIX
2021-11-04 16:26     ` Zoran Zaric
2021-10-14  9:32 ` [PATCH v3 28/28] Add DW_OP_LLVM_select_bit_piece " Zoran Zaric
2021-11-01 22:25   ` Lancelot SIX
2021-11-04 16:39     ` Zoran Zaric
2021-11-05 11:54 ` [PATCH v3 00/28] Allow location description on the DWARF stack Zaric, Zoran (Zare)

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