[PATCH 25/43] Add deref method to location description classes

Zoran Zaric via Gdb-patches
2021-03-01T14:47:28Z

Looking at the DWARF standard, the concept of reading from a location
seems to be too low level. 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 | 119 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 119 insertions(+)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index ef7adb1f959..ff9c88087d8 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -443,6 +443,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::shared_ptr<dwarf_value> deref
+ (struct frame_info *frame, const struct property_addr_info *addr_info,
+ struct type *type, size_t size = 0) const;
+
protected:
/* Architecture of the location. */
struct gdbarch *m_arch;
@@ -458,6 +470,43 @@ class dwarf_location : public dwarf_entry
bool m_initialised;
};

+std::shared_ptr<dwarf_value>
+dwarf_location::deref (struct frame_info *frame,
+ const struct 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 std::make_shared<dwarf_value> (read_buf.data (), type);
+}
+
/* Value entry found on a DWARF expression evaluation stack. */

class dwarf_value : public dwarf_entry
@@ -594,6 +643,10 @@ class dwarf_memory : public dwarf_location
size_t location_bit_limit, bool big_endian,
int *optimized, int *unavailable) const override;

+ std::shared_ptr<dwarf_value> deref
+ (struct frame_info *frame, const struct 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;
@@ -701,6 +754,72 @@ dwarf_memory::write (struct frame_info *frame, const gdb_byte *buf,
}
}

+std::shared_ptr<dwarf_value>
+dwarf_memory::deref (struct frame_info *frame,
+ const struct 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)
+ {
+ 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 std::make_shared<dwarf_value> (read_buf.data (), type);
+}
+
/* Register location description entry. */

class dwarf_register : public dwarf_location
--
2.17.1