public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Zoran Zaric <zoran.zaric@amd.com>
To: <gdb-patches@sourceware.org>
Subject: [PATCH v4 26/28] Add support for nested composite locations
Date: Fri, 5 Nov 2021 11:38:47 +0000	[thread overview]
Message-ID: <20211105113849.118800-27-zoran.zaric@amd.com> (raw)
In-Reply-To: <20211105113849.118800-1-zoran.zaric@amd.com>

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

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

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

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

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

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

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

gdb/ChangeLog:

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

include/ChangeLog:

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

gdb/testsuite/ChangeLog:

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

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


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

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

Reply instructions:

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

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

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

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

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

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

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