This is the mail archive of the gdb-cvs@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[binutils-gdb] Fix handling of DWARF register pieces on big-endian targets


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=03c8af18d1a8f359fd023696848bda488119da60

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.

Diff:
---
 gdb/ChangeLog                           |  7 +++++
 gdb/dwarf2loc.c                         | 56 ++++++++++++++++++++-------------
 gdb/testsuite/ChangeLog                 |  5 +++
 gdb/testsuite/gdb.dwarf2/var-access.exp | 25 +++++++++++++++
 4 files changed, 72 insertions(+), 21 deletions(-)

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index d1a400b..8c022a4 100644
--- 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.
 
diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index 6140ee6..a7447cb 100644
--- 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:
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 256d1fb..e5d303c 100644
--- 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.
 
diff --git a/gdb/testsuite/gdb.dwarf2/var-access.exp b/gdb/testsuite/gdb.dwarf2/var-access.exp
index 3ba2c08..c533b8d 100644
--- 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"


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]