diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c index f2349208412..6129f4e8ec9 100644 --- a/gdb/dwarf2/expr.c +++ b/gdb/dwarf2/expr.c @@ -391,6 +391,28 @@ public: 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; @@ -481,6 +503,14 @@ public: *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 @@ -502,6 +532,11 @@ public: 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; @@ -568,6 +603,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; + + *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. */ + 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 @@ -581,6 +672,11 @@ public: 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; @@ -627,6 +723,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 == nullptr) + 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. */ @@ -646,6 +789,15 @@ public: 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; @@ -712,6 +864,15 @@ public: 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; @@ -783,6 +944,11 @@ public: 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. */ @@ -848,6 +1014,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. */