From patchwork Fri Apr 7 17:38:13 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andreas Arnez X-Patchwork-Id: 19900 Received: (qmail 103794 invoked by alias); 7 Apr 2017 17:43:11 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 103228 invoked by uid 89); 7 Apr 2017 17:43:10 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-24.3 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_LAZY_DOMAIN_SECURITY, RCVD_IN_DNSWL_LOW autolearn=ham version=3.3.2 spammy=shine, formulas X-HELO: mx0a-001b2d01.pphosted.com Received: from mx0b-001b2d01.pphosted.com (HELO mx0a-001b2d01.pphosted.com) (148.163.158.5) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 07 Apr 2017 17:43:08 +0000 Received: from pps.filterd (m0098417.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.20/8.16.0.20) with SMTP id v37HcdWo044876 for ; Fri, 7 Apr 2017 13:43:08 -0400 Received: from e06smtp10.uk.ibm.com (e06smtp10.uk.ibm.com [195.75.94.106]) by mx0a-001b2d01.pphosted.com with ESMTP id 29pedttg02-1 (version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT) for ; Fri, 07 Apr 2017 13:43:08 -0400 Received: from localhost by e06smtp10.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Fri, 7 Apr 2017 18:43:06 +0100 Received: from b06cxnps3075.portsmouth.uk.ibm.com (9.149.109.195) by e06smtp10.uk.ibm.com (192.168.101.140) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Fri, 7 Apr 2017 18:43:04 +0100 Received: from d06av25.portsmouth.uk.ibm.com (d06av25.portsmouth.uk.ibm.com [9.149.105.61]) by b06cxnps3075.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id v37Hh4sa19464656 for ; Fri, 7 Apr 2017 17:43:04 GMT Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 8998611C058 for ; Fri, 7 Apr 2017 18:42:25 +0100 (BST) Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 6A9FA11C04C for ; Fri, 7 Apr 2017 18:42:25 +0100 (BST) Received: from oc1027705133.ibm.com (unknown [9.152.212.162]) by d06av25.portsmouth.uk.ibm.com (Postfix) with ESMTP for ; Fri, 7 Apr 2017 18:42:25 +0100 (BST) From: Andreas Arnez To: gdb-patches@sourceware.org Subject: [PATCH 6/9] Fix handling of DWARF register pieces on big-endian targets Date: Fri, 7 Apr 2017 19:38:13 +0200 In-Reply-To: <1491586736-21296-1-git-send-email-arnez@linux.vnet.ibm.com> References: <1491586736-21296-1-git-send-email-arnez@linux.vnet.ibm.com> X-TM-AS-GCONF: 00 x-cbid: 17040717-0040-0000-0000-00000362A29B X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 17040717-0041-0000-0000-000024DE8356 Message-Id: <1491586736-21296-7-git-send-email-arnez@linux.vnet.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2017-04-07_15:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 suspectscore=1 malwarescore=0 phishscore=0 adultscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1702020001 definitions=main-1704070144 X-IsSubscribed: yes 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(). For simplification, the variable buffer_size is dropped. 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. --- gdb/dwarf2loc.c | 74 +++++++++++++++++---------------- gdb/testsuite/gdb.dwarf2/var-access.exp | 32 ++++++++++++++ 2 files changed, 70 insertions(+), 36 deletions(-) diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c index 1f89a08..d13c0c5 100644 --- a/gdb/dwarf2loc.c +++ b/gdb/dwarf2loc.c @@ -1751,6 +1751,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) { @@ -1761,7 +1770,6 @@ read_pieced_value (struct value *v) struct piece_closure *c = (struct piece_closure *) value_computed_closure (v); size_t type_len; - size_t buffer_size = 0; std::vector buffer; int bits_big_endian = gdbarch_bits_big_endian (get_type_arch (value_type (v))); @@ -1805,13 +1813,9 @@ read_pieced_value (struct value *v) if (this_size_bits > type_len - offset) this_size_bits = type_len - 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; - if (buffer_size < this_size) - { - buffer_size = this_size; - buffer.reserve (buffer_size); - } intermediate_buffer = buffer.data (); /* Copy from the source to DEST_BUFFER. */ @@ -1822,22 +1826,22 @@ 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, - this_size, buffer.data (), - &optim, &unavail)) + if (!get_frame_register_bytes (frame, gdb_regnum, + source_offset_bits / 8, + this_size, buffer.data (), + &optim, &unavail)) { /* Just so garbage doesn't ever shine through. */ memset (buffer.data (), 0, this_size); @@ -1847,9 +1851,8 @@ read_pieced_value (struct value *v) if (unavail) mark_value_bits_unavailable (v, offset, this_size_bits); } - 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; @@ -1927,7 +1930,6 @@ write_pieced_value (struct value *to, struct value *from) struct piece_closure *c = (struct piece_closure *) value_computed_closure (to); size_t type_len; - size_t buffer_size = 0; std::vector buffer; int bits_big_endian = gdbarch_bits_big_endian (get_type_arch (value_type (to))); @@ -1972,7 +1974,7 @@ write_pieced_value (struct value *to, struct value *from) if (this_size_bits > type_len - offset) this_size_bits = type_len - 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; if (dest_offset_bits % 8 == 0 && source_offset_bits % 8 == 0 @@ -1983,11 +1985,7 @@ write_pieced_value (struct value *to, struct value *from) } else { - if (buffer_size < this_size) - { - buffer_size = this_size; - buffer.reserve (buffer_size); - } + buffer.reserve (this_size); source_buffer = buffer.data (); need_bitwise = 1; } @@ -1999,20 +1997,24 @@ 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) { + /* 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)) { @@ -2027,14 +2029,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/gdb.dwarf2/var-access.exp b/gdb/testsuite/gdb.dwarf2/var-access.exp index c6abc87..4787dfb 100644 --- a/gdb/testsuite/gdb.dwarf2/var-access.exp +++ b/gdb/testsuite/gdb.dwarf2/var-access.exp @@ -192,6 +192,18 @@ Dwarf::assemble $asm_file { piece 1 } SPECIAL_expr} } + # Register pieces for bitfield access. + 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} + } } } } @@ -206,6 +218,15 @@ if ![runto_main] { return -1 } +# Determine endianness. +set endian "little" +gdb_test_multiple "show endian" "determine endianness" { + -re ".* (big|little) endian.*$gdb_prompt $" { + set endian $expect_out(1,string) + pass "endianness: $endian" + } +} + # Byte-aligned memory pieces. gdb_test "print/d s1" " = \\{a = 2, b = 3, c = 0, d = 1\\}" \ "s1 == re-ordered buf" @@ -244,3 +265,14 @@ gdb_test_no_output "set var t1.y = 1234" gdb_test "print t1" " = \\{u = , x = -7, y = 1234, z = 340\\}" \ "verify t1" +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 = , 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"