|
|
e1d87d |
commit 03c8af18d1a8f359fd023696848bda488119da60
|
|
|
e1d87d |
Author: Andreas Arnez <arnez@linux.vnet.ibm.com>
|
|
|
e1d87d |
Date: Tue Jun 13 15:20:30 2017 +0200
|
|
|
e1d87d |
|
|
|
e1d87d |
Fix handling of DWARF register pieces on big-endian targets
|
|
|
e1d87d |
|
|
|
e1d87d |
For big-endian targets the logic in read/write_pieced_value tries to take
|
|
|
e1d87d |
a register piece from the LSB end. This requires offsets and sizes to be
|
|
|
e1d87d |
adjusted accordingly, and that's where the current implementation has some
|
|
|
e1d87d |
issues:
|
|
|
e1d87d |
|
|
|
e1d87d |
* The formulas for recalculating the bit- and byte-offsets into the
|
|
|
e1d87d |
register are wrong. They just happen to yield correct results if
|
|
|
e1d87d |
everything is byte-aligned and the piece's last byte belongs to the
|
|
|
e1d87d |
given value.
|
|
|
e1d87d |
|
|
|
e1d87d |
* After recalculating the bit offset into the register, the number of
|
|
|
e1d87d |
bytes to be copied from the register is not recalculated. Of course
|
|
|
e1d87d |
this does not matter if everything (particularly the piece size) is
|
|
|
e1d87d |
byte-aligned.
|
|
|
e1d87d |
|
|
|
e1d87d |
These issues are fixed. The size calculation is performed with a new
|
|
|
e1d87d |
helper function bits_to_bytes().
|
|
|
e1d87d |
|
|
|
e1d87d |
gdb/ChangeLog:
|
|
|
e1d87d |
|
|
|
e1d87d |
* dwarf2loc.c (bits_to_bytes): New function.
|
|
|
e1d87d |
(read_pieced_value): Fix offset calculations for register pieces
|
|
|
e1d87d |
on big-endian targets.
|
|
|
e1d87d |
(write_pieced_value): Likewise.
|
|
|
e1d87d |
|
|
|
e1d87d |
gdb/testsuite/ChangeLog:
|
|
|
e1d87d |
|
|
|
e1d87d |
* gdb.dwarf2/var-access.exp: Add test for non-byte-aligned
|
|
|
e1d87d |
register pieces.
|
|
|
e1d87d |
|
|
|
e1d87d |
### a/gdb/ChangeLog
|
|
|
e1d87d |
### b/gdb/ChangeLog
|
|
|
e1d87d |
## -1,5 +1,12 @@
|
|
|
e1d87d |
2017-06-13 Andreas Arnez <arnez@linux.vnet.ibm.com>
|
|
|
e1d87d |
|
|
|
e1d87d |
+ * dwarf2loc.c (bits_to_bytes): New function.
|
|
|
e1d87d |
+ (read_pieced_value): Fix offset calculations for register pieces
|
|
|
e1d87d |
+ on big-endian targets.
|
|
|
e1d87d |
+ (write_pieced_value): Likewise.
|
|
|
e1d87d |
+
|
|
|
e1d87d |
+2017-06-13 Andreas Arnez <arnez@linux.vnet.ibm.com>
|
|
|
e1d87d |
+
|
|
|
e1d87d |
* dwarf2loc.c (read_pieced_value): Remove buffer_size variable.
|
|
|
e1d87d |
(write_pieced_value): Likewise.
|
|
|
e1d87d |
|
|
|
e1d87d |
--- a/gdb/dwarf2loc.c
|
|
|
e1d87d |
+++ b/gdb/dwarf2loc.c
|
|
|
e1d87d |
@@ -1752,6 +1752,15 @@ copy_bitwise_tests (void)
|
|
|
e1d87d |
|
|
|
e1d87d |
#endif /* GDB_SELF_TEST */
|
|
|
e1d87d |
|
|
|
e1d87d |
+/* Return the number of bytes overlapping a contiguous chunk of N_BITS
|
|
|
e1d87d |
+ bits whose first bit is located at bit offset START. */
|
|
|
e1d87d |
+
|
|
|
e1d87d |
+static size_t
|
|
|
e1d87d |
+bits_to_bytes (ULONGEST start, ULONGEST n_bits)
|
|
|
e1d87d |
+{
|
|
|
e1d87d |
+ return (start % 8 + n_bits + 7) / 8;
|
|
|
e1d87d |
+}
|
|
|
e1d87d |
+
|
|
|
e1d87d |
static void
|
|
|
e1d87d |
read_pieced_value (struct value *v)
|
|
|
e1d87d |
{
|
|
|
e1d87d |
@@ -1804,7 +1813,7 @@ read_pieced_value (struct value *v)
|
|
|
e1d87d |
if (this_size_bits > max_offset - offset)
|
|
|
e1d87d |
this_size_bits = max_offset - offset;
|
|
|
e1d87d |
|
|
|
e1d87d |
- this_size = (this_size_bits + source_offset_bits % 8 + 7) / 8;
|
|
|
e1d87d |
+ this_size = bits_to_bytes (source_offset_bits, this_size_bits);
|
|
|
e1d87d |
buffer.reserve (this_size);
|
|
|
e1d87d |
source_offset = source_offset_bits / 8;
|
|
|
e1d87d |
intermediate_buffer = buffer.data ();
|
|
|
e1d87d |
@@ -1817,20 +1826,20 @@ read_pieced_value (struct value *v)
|
|
|
e1d87d |
struct frame_info *frame = frame_find_by_id (c->frame_id);
|
|
|
e1d87d |
struct gdbarch *arch = get_frame_arch (frame);
|
|
|
e1d87d |
int gdb_regnum = dwarf_reg_to_regnum_or_error (arch, p->v.regno);
|
|
|
e1d87d |
+ ULONGEST reg_bits = 8 * register_size (arch, gdb_regnum);
|
|
|
e1d87d |
int optim, unavail;
|
|
|
e1d87d |
- LONGEST reg_offset = source_offset;
|
|
|
e1d87d |
|
|
|
e1d87d |
if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG
|
|
|
e1d87d |
- && this_size < register_size (arch, gdb_regnum))
|
|
|
e1d87d |
+ && p->size < reg_bits)
|
|
|
e1d87d |
{
|
|
|
e1d87d |
/* Big-endian, and we want less than full size. */
|
|
|
e1d87d |
- reg_offset = register_size (arch, gdb_regnum) - this_size;
|
|
|
e1d87d |
- /* We want the lower-order THIS_SIZE_BITS of the bytes
|
|
|
e1d87d |
- we extract from the register. */
|
|
|
e1d87d |
- source_offset_bits += 8 * this_size - this_size_bits;
|
|
|
e1d87d |
+ source_offset_bits += reg_bits - p->size;
|
|
|
e1d87d |
}
|
|
|
e1d87d |
+ this_size = bits_to_bytes (source_offset_bits, this_size_bits);
|
|
|
e1d87d |
+ buffer.reserve (this_size);
|
|
|
e1d87d |
|
|
|
e1d87d |
- if (!get_frame_register_bytes (frame, gdb_regnum, reg_offset,
|
|
|
e1d87d |
+ if (!get_frame_register_bytes (frame, gdb_regnum,
|
|
|
e1d87d |
+ source_offset_bits / 8,
|
|
|
e1d87d |
this_size, buffer.data (),
|
|
|
e1d87d |
&optim, &unavail))
|
|
|
e1d87d |
{
|
|
|
e1d87d |
@@ -1844,7 +1853,7 @@ read_pieced_value (struct value *v)
|
|
|
e1d87d |
}
|
|
|
e1d87d |
|
|
|
e1d87d |
copy_bitwise (contents, dest_offset_bits,
|
|
|
e1d87d |
- intermediate_buffer, source_offset_bits % 8,
|
|
|
e1d87d |
+ buffer.data (), source_offset_bits % 8,
|
|
|
e1d87d |
this_size_bits, bits_big_endian);
|
|
|
e1d87d |
}
|
|
|
e1d87d |
break;
|
|
|
e1d87d |
@@ -1969,7 +1978,7 @@ write_pieced_value (struct value *to, struct value *from)
|
|
|
e1d87d |
if (this_size_bits > max_offset - offset)
|
|
|
e1d87d |
this_size_bits = max_offset - offset;
|
|
|
e1d87d |
|
|
|
e1d87d |
- this_size = (this_size_bits + dest_offset_bits % 8 + 7) / 8;
|
|
|
e1d87d |
+ this_size = bits_to_bytes (dest_offset_bits, this_size_bits);
|
|
|
e1d87d |
source_offset = source_offset_bits / 8;
|
|
|
e1d87d |
dest_offset = dest_offset_bits / 8;
|
|
|
e1d87d |
|
|
|
e1d87d |
@@ -1994,20 +2003,25 @@ write_pieced_value (struct value *to, struct value *from)
|
|
|
e1d87d |
struct frame_info *frame = frame_find_by_id (c->frame_id);
|
|
|
e1d87d |
struct gdbarch *arch = get_frame_arch (frame);
|
|
|
e1d87d |
int gdb_regnum = dwarf_reg_to_regnum_or_error (arch, p->v.regno);
|
|
|
e1d87d |
- int reg_offset = dest_offset;
|
|
|
e1d87d |
+ ULONGEST reg_bits = 8 * register_size (arch, gdb_regnum);
|
|
|
e1d87d |
|
|
|
e1d87d |
if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG
|
|
|
e1d87d |
- && this_size <= register_size (arch, gdb_regnum))
|
|
|
e1d87d |
+ && p->size <= reg_bits)
|
|
|
e1d87d |
{
|
|
|
e1d87d |
/* Big-endian, and we want less than full size. */
|
|
|
e1d87d |
- reg_offset = register_size (arch, gdb_regnum) - this_size;
|
|
|
e1d87d |
+ dest_offset_bits += reg_bits - p->size;
|
|
|
e1d87d |
}
|
|
|
e1d87d |
+ this_size = bits_to_bytes (dest_offset_bits, this_size_bits);
|
|
|
e1d87d |
+ buffer.reserve (this_size);
|
|
|
e1d87d |
|
|
|
e1d87d |
- if (need_bitwise)
|
|
|
e1d87d |
+ if (dest_offset_bits % 8 != 0 || this_size_bits % 8 != 0)
|
|
|
e1d87d |
{
|
|
|
e1d87d |
+ /* Data is copied non-byte-aligned into the register.
|
|
|
e1d87d |
+ Need some bits from original register value. */
|
|
|
e1d87d |
int optim, unavail;
|
|
|
e1d87d |
|
|
|
e1d87d |
- if (!get_frame_register_bytes (frame, gdb_regnum, reg_offset,
|
|
|
e1d87d |
+ if (!get_frame_register_bytes (frame, gdb_regnum,
|
|
|
e1d87d |
+ dest_offset_bits / 8,
|
|
|
e1d87d |
this_size, buffer.data (),
|
|
|
e1d87d |
&optim, &unavail))
|
|
|
e1d87d |
{
|
|
|
e1d87d |
@@ -2022,14 +2036,14 @@ write_pieced_value (struct value *to, struct value *from)
|
|
|
e1d87d |
"bitfield; containing word "
|
|
|
e1d87d |
"is unavailable"));
|
|
|
e1d87d |
}
|
|
|
e1d87d |
- copy_bitwise (buffer.data (), dest_offset_bits,
|
|
|
e1d87d |
- contents, source_offset_bits,
|
|
|
e1d87d |
- this_size_bits,
|
|
|
e1d87d |
- bits_big_endian);
|
|
|
e1d87d |
}
|
|
|
e1d87d |
|
|
|
e1d87d |
- put_frame_register_bytes (frame, gdb_regnum, reg_offset,
|
|
|
e1d87d |
- this_size, source_buffer);
|
|
|
e1d87d |
+ copy_bitwise (buffer.data (), dest_offset_bits % 8,
|
|
|
e1d87d |
+ contents, source_offset_bits,
|
|
|
e1d87d |
+ this_size_bits, bits_big_endian);
|
|
|
e1d87d |
+ put_frame_register_bytes (frame, gdb_regnum,
|
|
|
e1d87d |
+ dest_offset_bits / 8,
|
|
|
e1d87d |
+ this_size, buffer.data ());
|
|
|
e1d87d |
}
|
|
|
e1d87d |
break;
|
|
|
e1d87d |
case DWARF_VALUE_MEMORY:
|
|
|
e1d87d |
### a/gdb/testsuite/ChangeLog
|
|
|
e1d87d |
### b/gdb/testsuite/ChangeLog
|
|
|
e1d87d |
## -1,5 +1,10 @@
|
|
|
e1d87d |
2017-06-13 Andreas Arnez <arnez@linux.vnet.ibm.com>
|
|
|
e1d87d |
|
|
|
e1d87d |
+ * gdb.dwarf2/var-access.exp: Add test for non-byte-aligned
|
|
|
e1d87d |
+ register pieces.
|
|
|
e1d87d |
+
|
|
|
e1d87d |
+2017-06-13 Andreas Arnez <arnez@linux.vnet.ibm.com>
|
|
|
e1d87d |
+
|
|
|
e1d87d |
* gdb.dwarf2/var-access.exp: Add tests for accessing bit-fields
|
|
|
e1d87d |
located in one or more DWARF pieces.
|
|
|
e1d87d |
|
|
|
e1d87d |
--- a/gdb/testsuite/gdb.dwarf2/var-access.exp
|
|
|
e1d87d |
+++ b/gdb/testsuite/gdb.dwarf2/var-access.exp
|
|
|
e1d87d |
@@ -215,6 +215,19 @@ Dwarf::assemble $asm_file {
|
|
|
e1d87d |
piece 1
|
|
|
e1d87d |
} SPECIAL_expr}
|
|
|
e1d87d |
}
|
|
|
e1d87d |
+ # Register pieces for bitfield access: 4 bytes optimized
|
|
|
e1d87d |
+ # out, 3 bytes from r0, and 1 byte from r1.
|
|
|
e1d87d |
+ DW_TAG_variable {
|
|
|
e1d87d |
+ {name "t2"}
|
|
|
e1d87d |
+ {type :$struct_t_label}
|
|
|
e1d87d |
+ {location {
|
|
|
e1d87d |
+ piece 4
|
|
|
e1d87d |
+ regx [lindex $dwarf_regnum 0]
|
|
|
e1d87d |
+ piece 3
|
|
|
e1d87d |
+ regx [lindex $dwarf_regnum 1]
|
|
|
e1d87d |
+ piece 1
|
|
|
e1d87d |
+ } SPECIAL_expr}
|
|
|
e1d87d |
+ }
|
|
|
e1d87d |
}
|
|
|
e1d87d |
}
|
|
|
e1d87d |
}
|
|
|
e1d87d |
@@ -279,3 +292,15 @@ switch $endian {
|
|
|
e1d87d |
# val
|
|
|
e1d87d |
gdb_test "print/x a" " = \\{0x0, ${val}, 0x0, 0x0\\}" \
|
|
|
e1d87d |
"verify st1 through a"
|
|
|
e1d87d |
+
|
|
|
e1d87d |
+switch $endian { big {set val 0x7ffc} little {set val 0x3ffe00} }
|
|
|
e1d87d |
+gdb_test_no_output "set var \$[lindex $regname 0] = $val" \
|
|
|
e1d87d |
+ "init t2, first piece"
|
|
|
e1d87d |
+gdb_test_no_output "set var \$[lindex $regname 1] = 0" \
|
|
|
e1d87d |
+ "init t2, second piece"
|
|
|
e1d87d |
+gdb_test "print/d t2" " = \\{u = <optimized out>, x = 0, y = -1, z = 0\\}" \
|
|
|
e1d87d |
+ "initialized t2 from regs"
|
|
|
e1d87d |
+gdb_test_no_output "set var t2.y = 2641"
|
|
|
e1d87d |
+gdb_test_no_output "set var t2.z = -400"
|
|
|
e1d87d |
+gdb_test_no_output "set var t2.x = 200"
|
|
|
e1d87d |
+gdb_test "print t2.x + t2.y + t2.z" " = 2441"
|