In section 5.13 of DWARF5, the standard says Note that the stride can be negative I don't see anywhere in the standard besides this footnote that indicates it should be a signed value. In the array_size helper, the stride is calculated as Dwarf_Word stride = eltsize; if (INTUSE(dwarf_attr_integrate)(die, DW_AT_byte_stride, attr_mem) != NULL) { if (INTUSE(dwarf_formudata)(attr_mem, &stride) != 0) return -1; } else if (INTUSE(dwarf_attr_integrate)(die, DW_AT_bit_stride, attr_mem) != NULL) { if (INTUSE(dwarf_formudata)(attr_mem, &stride) != 0) return -1; if (stride % 8) /* XXX maybe compute in bits? */ return -1; stride /= 8; } Since we could be reading a negative integer, the use of dwarf_formudata would cause the total size to be incorrect. I don't have a reproducer, and I've not seen any binaries that have run across this. I just noticed it while reading through the source.
I have to admit that I don't understand what it means for a stride to be negative. It looks to me that a stride is like a size, it has to be positive. It would be good to have an example when the stride can be negative.
I asked around and John DelSignore came up with the following fortran example: = array.f95 = program f_prog integer*4, allocatable, target, dimension (:,:) :: big_array integer, dimension (:,:), pointer :: neg_array allocate (big_array(2000,1000)) neg_array => big_array(2000:1:-1,1000:1:-1) end program f_prog So, neg_array is a pointer to an array section where the elements of big_array are reversed. That is, neg_array(x,y) references big_array(2000-x+1,1000-y+1). In this example, the stride makes us go "backwards" into the array. But note that gfortran -g array.f95 produces DW_FORM_exprlocs for the DW_AT_byte_stride because almost all attributes of the array are dynamic at runtime: [ c9] array_type abbrev: 10 ordering (data1) col_major (1) data_location (exprloc) [ 0] push_object_address [ 1] deref allocated (exprloc) [ 0] push_object_address [ 1] deref [ 2] lit0 [ 3] ne type (ref4) [ 72] sibling (ref4) [ 106] [ db] subrange_type abbrev: 1 lower_bound (exprloc) [ 0] push_object_address [ 1] plus_uconst 48 [ 3] deref upper_bound (exprloc) [ 0] push_object_address [ 1] plus_uconst 56 [ 3] deref byte_stride (exprloc) [ 0] push_object_address [ 1] plus_uconst 40 [ 3] deref [ 4] push_object_address [ 5] plus_uconst 32 [ 7] deref [ 8] mul [ f0] subrange_type abbrev: 1 lower_bound (exprloc) [ 0] push_object_address [ 1] plus_uconst 72 [ 3] deref upper_bound (exprloc) [ 0] push_object_address [ 1] plus_uconst 80 [ 3] deref byte_stride (exprloc) [ 0] push_object_address [ 1] plus_uconst 64 [ 3] deref [ 4] push_object_address [ 5] plus_uconst 32 [ 7] deref [ 8] mul [ 106] array_type abbrev: 11 ordering (data1) col_major (1) data_location (exprloc) [ 0] push_object_address [ 1] deref associated (exprloc) [ 0] push_object_address [ 1] deref [ 2] lit0 [ 3] ne type (ref4) [ 72] [ 114] subrange_type abbrev: 1 lower_bound (exprloc) [ 0] push_object_address [ 1] plus_uconst 48 [ 3] deref upper_bound (exprloc) [ 0] push_object_address [ 1] plus_uconst 56 [ 3] deref byte_stride (exprloc) [ 0] push_object_address [ 1] plus_uconst 40 [ 3] deref [ 4] push_object_address [ 5] plus_uconst 32 [ 7] deref [ 8] mul [ 129] subrange_type abbrev: 1 lower_bound (exprloc) [ 0] push_object_address [ 1] plus_uconst 72 [ 3] deref upper_bound (exprloc) [ 0] push_object_address [ 1] plus_uconst 80 [ 3] deref byte_stride (exprloc) [ 0] push_object_address [ 1] plus_uconst 64 [ 3] deref [ 4] push_object_address [ 5] plus_uconst 32 [ 7] deref [ 8] mul Something dwarf_aggregate_size doesn't handle. And even if it could handle the expression, it doesn't know the object address or how to deref memory...
I was actually trying to make a Fortran example, but couldn't get one to work! Glad John was able to make one.