From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 30727 invoked by alias); 8 Dec 2010 23:47:08 -0000 Received: (qmail 30710 invoked by uid 22791); 8 Dec 2010 23:47:07 -0000 X-SWARE-Spam-Status: No, hits=-6.8 required=5.0 tests=AWL,BAYES_00,RCVD_IN_DNSWL_HI,SPF_HELO_PASS,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 08 Dec 2010 23:46:59 +0000 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id oB8NkwTZ018085 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Wed, 8 Dec 2010 18:46:58 -0500 Received: from mesquite.lan ([10.3.113.8]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id oB8Nkvt2023508 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES128-SHA bits=128 verify=NO) for ; Wed, 8 Dec 2010 18:46:58 -0500 Date: Wed, 08 Dec 2010 23:47:00 -0000 From: Kevin Buettner To: gdb-patches@sourceware.org Subject: [RFC] mips-tdep.c: Update mips_register_to_value(), et al... Message-ID: <20101208164657.7d9ce88e@mesquite.lan> Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2010-12/txt/msg00099.txt.bz2 Below is yet another patch that fixes a problem arising from the simulator catching UNPREDICTABLE behavior. This time though, it's for mips64 targets that are being run in 64-bit mode. (My earlier two patches dealt with 32-bit mode.) This patch fixes a failure in gdb.base/store.exp for mipsisa64-elf with target_board set to either mips-sim-idt64/-EB/-mips64 or mips-sim-idt64/-EL/-mips64. The log file sequence leading to the failure is as follows: tbreak wack_int Temporary breakpoint 4 at 0xffffffff800205e0: file /ironwood1/sourceware-mips/mipsisa64-elf/../src/gdb/testsuite/gdb.base/store.c, line 85. (gdb) PASS: gdb.base/store.exp: tbreak wack_int continue Continuing. Temporary breakpoint 4, wack_int (u=-1, v=-2) at /ironwood1/sourceware-mips/mipsisa64-elf/../src/gdb/testsuite/gdb.base/store.c:85 85 register int l = u, r = v; (gdb) PASS: gdb.base/store.exp: continue to wack_int next 86 l = add_int (l, r); (gdb) PASS: gdb.base/store.exp: var int l; next int print l $9 = -1 (gdb) PASS: gdb.base/store.exp: var int l; print old l, expecting -1 print r $10 = -2 (gdb) PASS: gdb.base/store.exp: var int l; print old r, expecting -2 set variable l = 4 (gdb) PASS: gdb.base/store.exp: var int l; setting l to 4 print l $11 = 4 (gdb) PASS: gdb.base/store.exp: var int l; print new l, expecting 4 next UNPREDICTABLE: PC = 0x800203a4 Quit (gdb) FAIL: gdb.base/store.exp: var int l; next over add call When executing the command "set variable l = 4", GDB is writing to the low 32 bits of the register containing `l'. The value was previously -1. Writing only the low 32 bits with a positive value causes a sign mismatch between the lower 32 bits and the upper 32 bits which eventually causes the sim to abort back to GDB. The instruction that causes the abort is the 32-bit addu instruction: => 0xffffffff800203a4 : addu v0,v1,v0 (gdb) p/x $v0 $8 = 0xfffffffffffffffe (gdb) p/x $v1 $9 = 0xffffffff00000004 (gdb) si UNPREDICTABLE: PC = 0x800203a4 (If the 64-bit daddu had been used instead, this abort would not have been triggered.) The patch below adds a case to mips_value_to_register() to ensure that sign extension is performed when writing a value shorter than 64-bits to a 64-bit register. It updates mips_convert_register_p() and mips_register_to_value() as well. Comments? (Can anyone think of better names for the two new functions that I introduced?) Kevin * mips-tdep.c (big_endian_4_byte_fp_reg_with_double_type_p) (eight_byte_gp_reg_with_shorter_type_p): New functions. (mips_convert_register_p): Invoke new functions above. (mips_register_to_value): Add case for fetching value shorter than 64 bits from a 64-bit register. (mips_value_to_register): Add case for storing value shorter than 64 bits into a 64-bit register. Index: mips-tdep.c =================================================================== RCS file: /cvs/src/src/gdb/mips-tdep.c,v retrieving revision 1.508 diff -u -p -r1.508 mips-tdep.c --- mips-tdep.c 28 Nov 2010 04:31:24 -0000 1.508 +++ mips-tdep.c 8 Dec 2010 22:49:57 -0000 @@ -626,7 +634,8 @@ set_mips64_transfers_32bit_regs (char *a /* Convert to/from a register and the corresponding memory value. */ static int -mips_convert_register_p (struct gdbarch *gdbarch, int regnum, struct type *type) +big_endian_4_byte_fp_reg_with_double_type_p (struct gdbarch *gdbarch, + int regnum, struct type *type) { return (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG && register_size (gdbarch, regnum) == 4 @@ -637,20 +646,89 @@ mips_convert_register_p (struct gdbarch && TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) == 8); } +static int +eight_byte_gp_reg_with_shorter_type_p (struct gdbarch *gdbarch, int regnum, + struct type *type) +{ + int num_regs = gdbarch_num_regs (gdbarch); + + return (register_size (gdbarch, regnum) == 8 + && regnum % num_regs > 0 && regnum % num_regs < 32 + && TYPE_LENGTH (type) < 8); +} + +static int +mips_convert_register_p (struct gdbarch *gdbarch, int regnum, struct type *type) +{ + return big_endian_4_byte_fp_reg_with_double_type_p (gdbarch, regnum, type) + || eight_byte_gp_reg_with_shorter_type_p (gdbarch, regnum, type); +} + static void mips_register_to_value (struct frame_info *frame, int regnum, struct type *type, gdb_byte *to) { - get_frame_register (frame, regnum + 0, to + 4); - get_frame_register (frame, regnum + 1, to + 0); + struct gdbarch *gdbarch = get_frame_arch (frame); + + if (big_endian_4_byte_fp_reg_with_double_type_p (gdbarch, regnum, type)) + { + get_frame_register (frame, regnum + 0, to + 4); + get_frame_register (frame, regnum + 1, to + 0); + } + else if (eight_byte_gp_reg_with_shorter_type_p (gdbarch, regnum, type)) + { + int len = TYPE_LENGTH (type); + if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) + get_frame_register_bytes (frame, regnum, 8 - len, len, to); + else + get_frame_register_bytes (frame, regnum, 0, len, to); + } + else + { + internal_error (__FILE__, __LINE__, + _("mips_register_to_value: unrecognized case")); + } } static void mips_value_to_register (struct frame_info *frame, int regnum, struct type *type, const gdb_byte *from) { - put_frame_register (frame, regnum + 0, from + 4); - put_frame_register (frame, regnum + 1, from + 0); + struct gdbarch *gdbarch = get_frame_arch (frame); + + if (big_endian_4_byte_fp_reg_with_double_type_p (gdbarch, regnum, type)) + { + put_frame_register (frame, regnum + 0, from + 4); + put_frame_register (frame, regnum + 1, from + 0); + } + else if (eight_byte_gp_reg_with_shorter_type_p (gdbarch, regnum, type)) + { + gdb_byte fill[8]; + int len = TYPE_LENGTH (type); + if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) + { + if (from[0] & 0x80) + store_signed_integer (fill, 8, BFD_ENDIAN_BIG, -1); + else + store_signed_integer (fill, 8, BFD_ENDIAN_BIG, 0); + put_frame_register_bytes (frame, regnum, 0, 8 - len, fill); + put_frame_register_bytes (frame, regnum, 8 - len, len, from); + } + else + { + if (from[len-1] & 0x80) + store_signed_integer (fill, 8, BFD_ENDIAN_LITTLE, -1); + else + store_signed_integer (fill, 8, BFD_ENDIAN_LITTLE, 0); + put_frame_register_bytes (frame, regnum, 0, len, from); + put_frame_register_bytes (frame, regnum, len, 8 - len, fill); + } + } + else + { + internal_error (__FILE__, __LINE__, + _("mips_value_to_register: unrecognized case")); + } } /* Return the GDB type object for the "standard" data type of data in