]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Add new classes that model DWARF stack element
authorZoran Zaric <Zoran.Zaric@amd.com>
Tue, 22 Sep 2020 16:16:33 +0000 (17:16 +0100)
committerZoran Zaric <zoran.zaric@amd.com>
Fri, 5 Nov 2021 11:46:38 +0000 (11:46 +0000)
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
gdb/value.c
gdb/value.h

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