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.