Blame SOURCES/gdb-rhbz1420304-s390x-21of35.patch

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"