[PATCH 23/43] Add read method to location description classes

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

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, 283 insertions(+), 22 deletions(-)

diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c
index 69be36fcf2d..35b2efa6cb5 100644
--- a/gdb/dwarf2/expr.c
+++ b/gdb/dwarf2/expr.c
@@ -285,6 +285,37 @@ 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 struct type *
+address_type (struct gdbarch *gdbarch, int addr_size)
+{
+ struct dwarf_gdbarch_types *types
+ = (struct dwarf_gdbarch_types *) gdbarch_data (gdbarch,
+ 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"),
+ 8 * addr_size);
+
+ if (types->dw_types[ndx] == NULL)
+ types->dw_types[ndx]
+ = arch_integer_type (gdbarch, HOST_CHAR_BIT * addr_size,
+ 0, "<signed DWARF address type>");
+
+ return types->dw_types[ndx];
+}
+
class dwarf_location;
class dwarf_memory;
class dwarf_value;
@@ -369,6 +400,27 @@ class dwarf_location : public dwarf_entry
return std::shared_ptr<dwarf_value> (nullptr);
}

+ /* Read contents from the descripbed 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 (struct 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. */
struct gdbarch *m_arch;
@@ -475,6 +527,14 @@ class dwarf_undefined : public dwarf_location
LONGEST bit_suboffset = 0)
: dwarf_location (arch, offset, bit_suboffset)
{}
+
+ void read (struct 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 : public dwarf_location
@@ -493,6 +553,11 @@ class dwarf_memory : public dwarf_location

std::shared_ptr<dwarf_value> to_value (struct type *type) override;

+ void read (struct 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;
@@ -504,6 +569,46 @@ dwarf_memory::to_value (struct type *type)
return std::make_shared<dwarf_value> (m_offset, type);
}

+void
+dwarf_memory::read (struct 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 : public dwarf_location
@@ -515,11 +620,55 @@ class dwarf_register : public dwarf_location
m_regnum (regnum)
{}

+ void read (struct 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 (struct 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;
+ int reg = dwarf_reg_to_regnum_or_error (m_arch, m_regnum);
+ ULONGEST reg_bits = HOST_CHAR_BIT * register_size (m_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. */
@@ -539,6 +688,10 @@ class dwarf_implicit : public dwarf_location
m_byte_order = byte_order;
}

+ void read (struct 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::unique_xmalloc_ptr<gdb_byte> m_contents;
@@ -550,6 +703,45 @@ class dwarf_implicit : public dwarf_location
enum bfd_endian m_byte_order;
};

+void
+dwarf_implicit::read (struct 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_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.get (),
+ total_bits_to_skip, bit_size, big_endian);
+}
+
/* Implicit pointer location description entry. */

class dwarf_implicit_pointer : public dwarf_location
@@ -565,6 +757,10 @@ class dwarf_implicit_pointer : public dwarf_location
m_addr_size (addr_size), m_die_offset (die_offset)
{}

+ void read (struct 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;
@@ -579,6 +775,44 @@ class dwarf_implicit_pointer : public dwarf_location
sect_offset m_die_offset;
};

+void
+dwarf_implicit_pointer::read (struct 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
+{
+ struct 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 : public dwarf_location
@@ -595,6 +829,10 @@ class dwarf_composite : public dwarf_location
m_pieces.emplace_back (location, bit_size);
}

+ void read (struct 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. */
@@ -617,6 +855,50 @@ class dwarf_composite : public dwarf_location
std::vector<struct piece> m_pieces;
};

+void
+dwarf_composite::read (struct 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].m_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].m_size;
+ LONGEST actual_bit_size = piece_bit_size;
+
+ if (actual_bit_size > bit_size)
+ actual_bit_size = bit_size;
+
+ m_pieces[i].m_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. */
@@ -1198,28 +1480,7 @@ sect_variable_value (sect_offset sect_off,
struct type *
dwarf_expr_context::address_type () const
{
- struct dwarf_gdbarch_types *types
- = (struct dwarf_gdbarch_types *) gdbarch_data (this->gdbarch,
- dwarf_arch_cookie);
- int ndx;
-
- if (this->addr_size == 2)
- ndx = 0;
- else if (this->addr_size == 4)
- ndx = 1;
- else if (this->addr_size == 8)
- ndx = 2;
- else
- error (_("Unsupported address size in DWARF expressions: %d bits"),
- 8 * this->addr_size);
-
- if (types->dw_types[ndx] == NULL)
- types->dw_types[ndx]
- = arch_integer_type (this->gdbarch,
- 8 * this->addr_size,
- 0, "<signed DWARF address type>");
-
- return types->dw_types[ndx];
+ return ::address_type (this->gdbarch, this->addr_size);
}

/* Create a new context for the expression evaluator. */
--
2.17.1