Add gdb.fortran/vla-stride.exp and report a bug (was: Re: [review] gdb/fortran: array stride support)

Message ID 20200118230433.GC3865@embecosm.com
State New, archived
Headers

Commit Message

Andrew Burgess Jan. 18, 2020, 11:04 p.m. UTC
  * Sergio Durigan Junior <sergiodj@redhat.com> [2020-01-13 22:46:33 -0500]:

> On Thursday, November 14 2019, Andrew Burgess wrote:
> 
> > Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/627
> > ......................................................................
> >
> > gdb/fortran: array stride support
> > [...]
> 
> Hey Andrew,
> 
> I found a problem with this patch, and I'd like to know if you've
> noticed this as well.  I first encountered the problem while doing
> downstream work on Fedora GDB for Fedora Rawhide; as you are probably
> aware, we carry *a lot* of local Fortran VLA patches on Fedora GDB (if
> you're not aware about this, feel free to get in touch with me and I'll
> be more than happy to explain the situation to you).  However, I am able
> to reproduce the problem on upstream GDB as well.
> 
> On Fedora GDB, we carry a testcase called gdb.fortran/vla-stride.exp.  I'm
> attaching it to this message.  One of its tests fails with:
> 
>   (gdb) print pvla
>   Cannot access memory at address 0x426000
>   FAIL: gdb.fortran/vla-stride.exp: print single-element

Sergio,

First, apologies for not replying sooner, I completely missed this
mail.  My bad!

Thanks for the bug report.  Yes I'm aware that Fedora carries some
Fortran patches, its on my (ever growing) todo list that I should take
a look at them one day.  It kind-of sucks that my top of tree GDB is
sometimes not as good as my slightly older distro-installed GDB!

I put together a patch for this issue (see below) it passes your test
case on my machine (with no other regressions), but it would be neat
if you could confirm it resolves the issue for you.

This particular case is about negative array strides, which in general
(right now) wont work in GDB ... however, this particular case is
special, it's a 1 element array with a negative array stride, that we
can do, if we don't deliberately sabotage ourselves by treating the
negative stride as unsigned.

As for negative array strides in general, I'm working on this, but
it's a big change and I don't know when it will be finished.

Anyway, patch below.  Feedback welcome.  I'll push this in a week or
so if I don't get any negative feedback.

One question - I included your testcase in this patch, I just wanted
to check that this is OK for upstream (w.r.t. copyright assignment, etc)?

Thanks,
Andrew

---

commit 6cedcaebf82d3a1b4e6defd5a07b02c0807a29af
Author: Andrew Burgess <andrew.burgess@embecosm.com>
Date:   Sat Jan 18 22:38:29 2020 +0000

    gdb/fortran: Support negative array stride in one limited case
    
    This commit adds support for negative Fortran array stride in one
    limited case, that is the case of a single element array with a
    negative array stride.
    
    The changes in this commit will be required in order for more general
    negative array stride support to work correctly, however, right now
    other problems in GDB prevent negative array strides from working in
    the general case.
    
    The reason negative array strides don't currently work in the general
    case is that when dealing with such arrays, the base address for the
    objects data is actually the highest addressed element, subsequent
    elements are then accessed with a negative offset from that address.
    
    Currently GDB supports positive type sizes, and having the base
    address of an object being its lowest address.  I am working on a
    patch series to add more general negative array stride support,
    however, this is a much larger piece of work.
    
    The changes here can be summarised as, stop treating signed values as
    unsigned, specifically, the array stride, and offsets calculated using
    the array stride.
    
    The test for this issue was posted to the list by Sergio:
    
      https://sourceware.org/ml/gdb-patches/2020-01/msg00360.html
    
    Change-Id: I9087c767d1640946a0b876ea0920481e18ffed7c
  

Comments

Sergio Durigan Junior Feb. 5, 2020, 4:38 p.m. UTC | #1
On Saturday, January 18 2020, Andrew Burgess wrote:

> * Sergio Durigan Junior <sergiodj@redhat.com> [2020-01-13 22:46:33 -0500]:
>
>> On Thursday, November 14 2019, Andrew Burgess wrote:
>> 
>> > Change URL: https://gnutoolchain-gerrit.osci.io/r/c/binutils-gdb/+/627
>> > ......................................................................
>> >
>> > gdb/fortran: array stride support
>> > [...]
>> 
>> Hey Andrew,
>> 
>> I found a problem with this patch, and I'd like to know if you've
>> noticed this as well.  I first encountered the problem while doing
>> downstream work on Fedora GDB for Fedora Rawhide; as you are probably
>> aware, we carry *a lot* of local Fortran VLA patches on Fedora GDB (if
>> you're not aware about this, feel free to get in touch with me and I'll
>> be more than happy to explain the situation to you).  However, I am able
>> to reproduce the problem on upstream GDB as well.
>> 
>> On Fedora GDB, we carry a testcase called gdb.fortran/vla-stride.exp.  I'm
>> attaching it to this message.  One of its tests fails with:
>> 
>>   (gdb) print pvla
>>   Cannot access memory at address 0x426000
>>   FAIL: gdb.fortran/vla-stride.exp: print single-element
>
> Sergio,
>
> First, apologies for not replying sooner, I completely missed this
> mail.  My bad!

That's totally fine -- I also took too long to reply.

> Thanks for the bug report.  Yes I'm aware that Fedora carries some
> Fortran patches, its on my (ever growing) todo list that I should take
> a look at them one day.  It kind-of sucks that my top of tree GDB is
> sometimes not as good as my slightly older distro-installed GDB!

Hah, yeah :-).  It'd be great to have your help with the patches; let me
know when you can dedicate some time, and we can coordinate efforts.

> I put together a patch for this issue (see below) it passes your test
> case on my machine (with no other regressions), but it would be neat
> if you could confirm it resolves the issue for you.

Thanks a lot.  I've just confirmed that the patch indeed fixes the
issue.

> One question - I included your testcase in this patch, I just wanted
> to check that this is OK for upstream (w.r.t. copyright assignment, etc)?

So, as we discussed on IRC, I don't have the exact authorship
information for the testcase, but I think it was written by Bernhard
Heckel <bernhard dot heckel at intel dot com>.  I'm almost sure that
this was contributed by Intel, and if that's the case, then they have
copyright assignment on file with us, so it should be fine to push the
patch as is.

I'll let you know if I find more info on this, but apparently (based on
our IRC talk) you're going to write a new test anyway, so please don't
wait for me.

Cheers,
  

Patch

diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 1d5bfd4bc20..d1201b1df9a 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -1223,7 +1223,7 @@  create_array_type_with_stride (struct type *result_type,
 	  && !type_not_allocated (result_type)))
     {
       LONGEST low_bound, high_bound;
-      unsigned int stride;
+      int stride;
 
       /* If the array itself doesn't provide a stride value then take
 	 whatever stride the range provides.  Don't update BIT_STRIDE as
@@ -1241,9 +1241,18 @@  create_array_type_with_stride (struct type *result_type,
 	 In such cases, the array length should be zero.  */
       if (high_bound < low_bound)
 	TYPE_LENGTH (result_type) = 0;
-      else if (stride > 0)
-	TYPE_LENGTH (result_type) =
-	  (stride * (high_bound - low_bound + 1) + 7) / 8;
+      else if (stride != 0)
+	{
+	  /* Ensure that the type length is always positive, even in the
+	     case where (for example in Fortran) we have a negative
+	     stride.  It is possible to have a single element array with a
+	     negative stride in Fortran (this doesn't mean anything
+	     special, it's still just a single element array) so do
+	     consider that case when touching this code.  */
+	  LONGEST element_count = abs (high_bound - low_bound + 1);
+	  TYPE_LENGTH (result_type)
+	    = ((abs (stride) * element_count) + 7) / 8;
+	}
       else
 	TYPE_LENGTH (result_type) =
 	  TYPE_LENGTH (element_type) * (high_bound - low_bound + 1);
diff --git a/gdb/testsuite/gdb.fortran/vla-stride.exp b/gdb/testsuite/gdb.fortran/vla-stride.exp
new file mode 100644
index 00000000000..15573e22cb3
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/vla-stride.exp
@@ -0,0 +1,44 @@ 
+# Copyright 2016-2020 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+standard_testfile ".f90"
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} \
+    {debug f90 quiet}] } {
+    return -1
+}
+
+if ![runto MAIN__] then {
+    perror "couldn't run to breakpoint MAIN__"
+    continue
+}
+
+gdb_breakpoint [gdb_get_line_number "re-reverse-elements"]
+gdb_continue_to_breakpoint "re-reverse-elements"
+gdb_test "print pvla" " = \\\(1, 2, 3, 4, 5, 6, 7, 8, 9, 10\\\)" \
+  "print re-reverse-elements"
+gdb_test "print pvla(1)" " = 1" "print first re-reverse-element"
+gdb_test "print pvla(10)" " = 10" "print last re-reverse-element"
+
+gdb_breakpoint [gdb_get_line_number "odd-elements"]
+gdb_continue_to_breakpoint "odd-elements"
+gdb_test "print pvla" " = \\\(1, 3, 5, 7, 9\\\)" "print odd-elements"
+gdb_test "print pvla(1)" " = 1" "print first odd-element"
+gdb_test "print pvla(5)" " = 9" "print last odd-element"
+
+gdb_breakpoint [gdb_get_line_number "single-element"]
+gdb_continue_to_breakpoint "single-element"
+gdb_test "print pvla" " = \\\(5\\\)" "print single-element"
+gdb_test "print pvla(1)" " = 5" "print one single-element"
diff --git a/gdb/testsuite/gdb.fortran/vla-stride.f90 b/gdb/testsuite/gdb.fortran/vla-stride.f90
new file mode 100644
index 00000000000..22b8a65278e
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/vla-stride.f90
@@ -0,0 +1,29 @@ 
+! Copyright 2016-2020 Free Software Foundation, Inc.
+!
+! This program is free software; you can redistribute it and/or modify
+! it under the terms of the GNU General Public License as published by
+! the Free Software Foundation; either version 3 of the License, or
+! (at your option) any later version.
+!
+! This program is distributed in the hope that it will be useful,
+! but WITHOUT ANY WARRANTY; without even the implied warranty of
+! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+! GNU General Public License for more details.
+!
+! You should have received a copy of the GNU General Public License
+! along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+program vla_stride
+  integer, target, allocatable :: vla (:)
+  integer, pointer :: pvla (:)
+
+  allocate(vla(10))
+  vla = (/ (I, I = 1,10) /)
+
+  pvla => vla(10:1:-1)
+  pvla => pvla(10:1:-1)
+  pvla => vla(1:10:2)   ! re-reverse-elements
+  pvla => vla(5:4:-2)   ! odd-elements
+
+  pvla => null()        ! single-element
+end program vla_stride
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 79b148602bb..be0e0731bee 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -187,7 +187,7 @@  value_subscripted_rvalue (struct value *array, LONGEST index, LONGEST lowerbound
 {
   struct type *array_type = check_typedef (value_type (array));
   struct type *elt_type = check_typedef (TYPE_TARGET_TYPE (array_type));
-  ULONGEST elt_size = type_length_units (elt_type);
+  LONGEST elt_size = type_length_units (elt_type);
 
   /* Fetch the bit stride and convert it to a byte stride, assuming 8 bits
      in a byte.  */
@@ -199,7 +199,7 @@  value_subscripted_rvalue (struct value *array, LONGEST index, LONGEST lowerbound
       elt_size = stride / (unit_size * 8);
     }
 
-  ULONGEST elt_offs = elt_size * (index - lowerbound);
+  LONGEST elt_offs = elt_size * (index - lowerbound);
 
   if (index < lowerbound
       || (!TYPE_ARRAY_UPPER_BOUND_IS_UNDEFINED (array_type)