https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92775

            Bug ID: 92775
           Summary: Incorrect expression in DW_AT_byte_stride on an array
           Product: gcc
           Version: unknown
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: fortran
          Assignee: unassigned at gcc dot gnu.org
          Reporter: andrew.burgess at embecosm dot com
  Target Milestone: ---

Created attachment 47411
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=47411&action=edit
Example.

1. Unpack the example, and run 'make'.  This creates a test binary
   called 'test', and the DWARF from that binary is placed into
   'test.dwarf'.  Initially I'm using GCC 7.4.0.

2. In the generated 'test.dwarf' Find the DW_TAG_variable for
   'point_dimension', note its DW_AT_type and DW_AT_location.  For me
   I have:

   <2><e9>: Abbrev Number: 10 (DW_TAG_variable)
      <ea>   DW_AT_name        : (indirect string, offset: 0x0):
point_dimension
      <ee>   DW_AT_decl_file   : 1
      <ef>   DW_AT_decl_line   : 13
      <f0>   DW_AT_type        : <0x18a>
      <f4>   DW_AT_location    : 9 byte block: 3 80 10 60 0 0 0 0 0      
(DW_OP_addr: 601080)
   ...
   <1><18a>: Abbrev Number: 16 (DW_TAG_array_type)
      <18b>   DW_AT_data_location: 2 byte block: 97 6    
(DW_OP_push_object_address; DW_OP_deref)
      <18e>   DW_AT_associated  : 4 byte block: 97 6 30 2e       
(DW_OP_push_object_address; DW_OP_deref; DW_OP_lit0; DW_OP_ne)
      <193>   DW_AT_type        : <0x5d>
   <2><197>: Abbrev Number: 17 (DW_TAG_subrange_type)
      <198>   DW_AT_lower_bound : 4 byte block: 97 23 20 6       
(DW_OP_push_object_address; DW_OP_plus_uconst: 32; DW_OP_deref)
      <19d>   DW_AT_upper_bound : 4 byte block: 97 23 28 6       
(DW_OP_push_object_address; DW_OP_plus_uconst: 40; DW_OP_deref)
      <1a2>   DW_AT_byte_stride : 15 byte block: 97 23 18 6 3 b0 10 60 0 0 0 0
0 6 1e     (DW_OP_push_object_address; DW_OP_plus_uconst: 24; DW_OP_deref;
DW_OP_addr: 6010b0; DW_OP_deref; DW_OP_mul)

3. Figure out the expression to read the DW_AT_byte_stride, from the above it
will be:

   ((*(0x601080 + 24)) * (*0x6010b0))

4. Run the test program, this just confirms what we expect the value
   of 'point_dimension' to be, which is: { 2, 2, 2, 2, 2, 2, 2, 2, 2 }.

5. Now fire up GDB on the test program:

   $ gdb test
   (gdb) break 18
   (gdb) run
   (gdb) p/d ((*(0x601080 + 24)) * (*0x6010b0))
   $1 = 24

   # So the stride appears to be 24.  Now to check, first, where's the
   # first element:

   (gdb) p &point_dimension(1)
   $2 = (PTR TO -> ( integer(kind=8) )) 0x7fffffffccd8

   # Now lets check the stride is correct by examining all the
   # remaining elements:

   (gdb) x/1w 0x7fffffffccd8 + (24 * 0)
   0x7fffffffccd8:      2
   (gdb) x/1w 0x7fffffffccd8 + (24 * 1)
   0x7fffffffccf0:      2
   (gdb) x/1w 0x7fffffffccd8 + (24 * 2)
   0x7fffffffcd08:      2
   (gdb) x/1w 0x7fffffffccd8 + (24 * 3)
   0x7fffffffcd20:      2
   (gdb) x/1w 0x7fffffffccd8 + (24 * 4)
   0x7fffffffcd38:      2
   (gdb) x/1w 0x7fffffffccd8 + (24 * 5)
   0x7fffffffcd50:      2
   (gdb) x/1w 0x7fffffffccd8 + (24 * 6)
   0x7fffffffcd68:      2
   (gdb) x/1w 0x7fffffffccd8 + (24 * 7)
   0x7fffffffcd80:      2
   (gdb) x/1w 0x7fffffffccd8 + (24 * 8)
   0x7fffffffcd98:      2

   # So it looks like a stride of 24 is correct.  Based on the code
   # this is what I would expect.

6. Now recompile the test with a later version of GCC.  I've tested
   8.3.0 and 9.2.0, plus a version from trunk from mid-October 2019.
   The data below is from 9.2.0:

   <2><e9>: Abbrev Number: 10 (DW_TAG_variable)
      <ea>   DW_AT_name        : (indirect string, offset: 0x0):
point_dimension
      <ee>   DW_AT_decl_file   : 1
      <ef>   DW_AT_decl_line   : 13
      <f0>   DW_AT_type        : <0x10f>
      <f4>   DW_AT_location    : 9 byte block: 3 80 10 60 0 0 0 0 0      
(DW_OP_addr: 601080)
   ...
   <1><10f>: Abbrev Number: 13 (DW_TAG_array_type)
      <110>   DW_AT_data_location: 2 byte block: 97 6    
(DW_OP_push_object_address; DW_OP_deref)
      <113>   DW_AT_associated  : 4 byte block: 97 6 30 2e       
(DW_OP_push_object_address; DW_OP_deref; DW_OP_lit0; DW_OP_ne)
      <118>   DW_AT_type        : <0x5d>
   <2><11c>: Abbrev Number: 14 (DW_TAG_subrange_type)
      <11d>   DW_AT_lower_bound : 4 byte block: 97 23 30 6       
(DW_OP_push_object_address; DW_OP_plus_uconst: 48; DW_OP_deref)
      <122>   DW_AT_upper_bound : 4 byte block: 97 23 38 6       
(DW_OP_push_object_address; DW_OP_plus_uconst: 56; DW_OP_deref)
      <127>   DW_AT_byte_stride : 6 byte block: 97 23 28 6 38 1e 
(DW_OP_push_object_address; DW_OP_plus_uconst: 40; DW_OP_deref; DW_OP_lit8;
DW_OP_mul)

7. Notice that the DW_AT_byte_stride expression has changed, it now
   looks like this:

   ((*(0x601080 + 40)) * 8)

8. Before we validate this in GDB, for our sanity rerun the test
   program and confirm that it does the correct thing at run time, it
   still prints the array as 9 elements, all containing the value 2.

9. Now fire up GDB on the test program:

   $ gdb test
   (gdb) break 18
   (gdb) run
   (gdb) p/d ((*(0x601080 + 40)) * 8)
   $1 = 8

   # So now the stride is reported as 8.  This seems unlikely, but
   # lets try it.  Where's the first element.

   (gdb) p &point_dimension(1)
   $2 = (PTR TO -> ( integer(kind=8) )) 0x7fffffffcba8

   # Now lets check all the other elements are in the correct place:

   (gdb) x/1w 0x7fffffffcba8 + (8 * 0)
   0x7fffffffcba8:      2
   (gdb) x/1w 0x7fffffffcba8 + (8 * 1)
   0x7fffffffcbb0:      3
   (gdb) x/1w 0x7fffffffcba8 + (8 * 2)
   0x7fffffffcbb8:      1
   (gdb) x/1w 0x7fffffffcba8 + (8 * 3)
   0x7fffffffcbc0:      2
   (gdb) x/1w 0x7fffffffcba8 + (8 * 4)
   0x7fffffffcbc8:      3
   (gdb) x/1w 0x7fffffffcba8 + (8 * 5)
   0x7fffffffcbd0:      1
   (gdb) x/1w 0x7fffffffcba8 + (8 * 6)
   0x7fffffffcbd8:      2
   (gdb) x/1w 0x7fffffffcba8 + (8 * 7)
   0x7fffffffcbe0:      3
   (gdb) x/1w 0x7fffffffcba8 + (8 * 8)
   0x7fffffffcbe8:      1

   # Clearly this is not correct.

10. The conclusion is that the DW_AT_byte_stride attribute of the
    DW_TAG_subrange_type for Fortran arrays is currently being generated
    incorrectly.

Reply via email to