From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 3684 invoked by alias); 24 Mar 2005 04:14:21 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 3643 invoked from network); 24 Mar 2005 04:14:12 -0000 Received: from unknown (HELO priv-edtnes56.telusplanet.net) (199.185.220.220) by sourceware.org with SMTP; 24 Mar 2005 04:14:12 -0000 Received: from takamaka.act-europe.fr ([142.179.108.108]) by priv-edtnes56.telusplanet.net (InterMail vM.6.01.04.00 201-2131-118-20041027) with ESMTP id <20050324041407.DBEZ26152.priv-edtnes56.telusplanet.net@takamaka.act-europe.fr> for ; Wed, 23 Mar 2005 21:14:07 -0700 Received: by takamaka.act-europe.fr (Postfix, from userid 507) id 614E247DC0; Wed, 23 Mar 2005 20:14:07 -0800 (PST) Date: Thu, 24 Mar 2005 04:14:00 -0000 From: Joel Brobecker To: gdb-patches@sources.redhat.com Subject: [RFC/mips] Problem with fetching/setting 32 bit registers Message-ID: <20050324041407.GG1324@adacore.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.4i X-SW-Source: 2005-03/txt/msg00294.txt.bz2 Hello, I think the perfect person to ask this would have been Andrew, but he's been away for a while now (good for him, though). Anyway, I think others have a good knowledge of this port, so hopefully I can get some help in solving my issue. I know what happens, and I have a patch that gives me very results, but I think I did not fix it the proper way. This is on mips-irix. A customer of ours was debugging his program that was misfunctioning. He was suspecting a float overflow. So he tried changing a flag in the FSR register so that divisions leading to an infinity would trigger a signal rather than generate an Inf value. That's when he discovered that the FSR value read by GDB was incorrect, and that he was also unable to change it. To reproduce the problem, we have a small testcase. Sources are pasted at the end of this message. For those who don't understand Ada, all it does is basically do a float division by a very small number, leading to an Inf result. What we're trying to do is check the FSR register mask, modify it before the division is made, and verify that the division now causes a SIGFPE signal to be raised. This is what GDB does, using a recent version from CVS head: (gdb) start (gdb) p /x $fsr !!! -> $1 = 0x0 (gdb) set $fsr := 0x01000e00 (gdb) p /x $fsr !!! -> $2 = 0x0 (gdb) c Continuing. !!! -> overflow did not crash..result: +Inf**************** Program exited normally. For $1, the actual value is: 0x1000000. And for $2, we expect to see the value we set (0x01000e00), not 0x0. And as a confirmation that the value was incorrectly set we see the program running past the division without any SIGFPE being raised. I think this regression has been introduced when the mips port was converted to the new register cache mechanism, where the distinction between raw and cooked registers is made. It used to work with 5.1.1 for instance (although not perfectly, GDB was printing this register as a 64 bits value, which is not true). What I found was that the problem was related to the fact that the FSR register is 32 bits. So the cooked register type was set to a 32 bits type, while underneath, the value provided by the kernel is located in a 64 bits buffer. And looking close, I found that we're reading and writing th wrong end of the buffer :-(. Here is the relevant code using when reading a pseudo register whose size is smaller than the size of the cooked register: else if (register_size (gdbarch, rawnum) > register_size (gdbarch, cookednum)) { if (gdbarch_tdep (gdbarch)->mips64_transfers_32bit_regs_p || TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE) regcache_raw_read_part (regcache, rawnum, 0, 4, buf); else regcache_raw_read_part (regcache, rawnum, 4, 4, buf); In our case (mips-irix), we have a big-endian byte order, and therefore read the register value from the last 4 bytes, while I found out that they are actually in the first 4. The gdbarch_tdep (gdbarch)->mips64_transfers_32bit_regs_p check gave me the idea of trying to set remote-mips64-transfers-32bit-regs, and this gave me the expected result: (gdb) set remote-mips64-transfers-32bit-regs (gdb) start (gdb) info reg fsr fsr: 0x1000000 (gdb) set $fsr := 0x01000e00 (gdb) info reg fsr fsr: 0x1000e00 (gdb) cont Continuing. Program received signal SIGFPE, Arithmetic exception. 0x10004188 in hello () at hello.adb:7 7 f := 1.0e200/value; So this confirmed that we were reading the register value from the wrong end. But this is not the right fix, since this flag actually tells GDB that all registers are 32 bit, which is wrong for mips-irix. All general registers are 64 bits. I think I understand the logic behind having deciding to use a zero offset in the little-endian case while using the second half for big-endian targets. And that suggests that mips-irix is an exception to the usual rule. I have tried the following change, just as an experiment: diff -u -p -r1.5 mips-tdep.c --- mips-tdep.c 17 Mar 2005 04:43:28 -0000 1.5 +++ mips-tdep.c 23 Mar 2005 00:30:38 -0000 @@ -606,7 +606,8 @@ mips_pseudo_register_read (struct gdbarc register_size (gdbarch, cookednum)) { if (gdbarch_tdep (gdbarch)->mips64_transfers_32bit_regs_p - || TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE) + || TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE + || gdbarch_osabi (current_gdbarch) == GDB_OSABI_IRIX) regcache_raw_read_part (regcache, rawnum, 0, 4, buf); else regcache_raw_read_part (regcache, rawnum, 4, 4, buf); @@ -628,7 +629,8 @@ mips_pseudo_register_write (struct gdbar register_size (gdbarch, cookednum)) { if (gdbarch_tdep (gdbarch)->mips64_transfers_32bit_regs_p - || TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE) + || TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE + || gdbarch_osabi (current_gdbarch) == GDB_OSABI_IRIX) regcache_raw_write_part (regcache, rawnum, 0, 4, buf); else regcache_raw_write_part (regcache, rawnum, 4, 4, buf); And it works very well. In fact, not only does it fix the problem exposed here, but it does help a lot in the testsuite as well (with function calls, and signal testcases). But I am hesitating a bit. It looks a bit like a hack to be specifying specifically IRIX here. I am afraid that there might be another way of fixing this more cleanly. But I don't see anything. One idea I had was to add yet another flag in the tdep part to say force the side where to look. But that wouldn't very practical either. So I'm left with the change above. Any comments? Thanks, -- Joel -- hello.adb with text_io; use text_io; with data; use data; procedure hello is begin f := 1.0e200/value; put_line ("overflow did not crash..result: " & long_float'image(f)); end; --- data.ads package data is f : long_float; value : long_float := 1.0e-300; end; ---