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