Bug 77589 - [6/7 Regression] fortran: Missing DW_AT_byte_stride for an array record field selection
Summary: [6/7 Regression] fortran: Missing DW_AT_byte_stride for an array record field...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: debug (show other bugs)
Version: 6.2.1
: P4 normal
Target Milestone: 5.5
Assignee: Jakub Jelinek
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-09-14 12:51 UTC by Jan Kratochvil
Modified: 2018-07-31 15:01 UTC (History)
4 users (show)

See Also:
Host:
Target: x86_64-*-*
Build:
Known to work:
Known to fail:
Last reconfirmed: 2016-09-15 00:00:00


Attachments
dwarf-stridex.f90 (232 bytes, text/plain)
2016-09-14 12:51 UTC, Jan Kratochvil
Details
gcc7-pr77589.patch (4.30 KB, patch)
2017-02-08 16:55 UTC, Jakub Jelinek
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Jan Kratochvil 2016-09-14 12:51:09 UTC
Fedora testcase: gdb.fortran/dwarf-stride.exp
! File written by Alan Matsuoka.

FAIL: gcc-6.2.1-1.fc26.x86_64
PASS: gcc-4.8.5-4.el7.x86_64

gfortran -o dwarf-stridex dwarf-stridex.f90 -Wall -g;../gdb ./dwarf-stridex -batch -ex 'b 14' -ex r -ex 'p c40pt(2)'

p c40pt(2)^M
$2 = '\001\000\000\000\061-hello', ' ' <repeats 29 times>^M
(gdb) FAIL: gdb.fortran/dwarf-stride.exp: p c40pt(2)

p c40pt(2)^M
$2 = '1-hello', ' ' <repeats 33 times>^M
(gdb) PASS: gdb.fortran/dwarf-stride.exp: p c40pt(2)

FAIL:
 <2><174>: Abbrev Number: 18 (DW_TAG_subrange_type)
    <175>   DW_AT_lower_bound : (DW_OP_push_object_address; DW_OP_plus_uconst: 32; DW_OP_deref)
    <17a>   DW_AT_upper_bound : (DW_OP_push_object_address; DW_OP_plus_uconst: 40; DW_OP_deref)

PASS:
 <2><127>: Abbrev Number: 14 (DW_TAG_subrange_type)
    <128>   DW_AT_lower_bound : (DW_OP_push_object_address; DW_OP_plus_uconst: 32; DW_OP_deref)
    <12d>   DW_AT_upper_bound : (DW_OP_push_object_address; DW_OP_plus_uconst: 40; DW_OP_deref)
    <132>   DW_AT_byte_stride : (DW_OP_push_object_address; DW_OP_plus_uconst: 24; DW_OP_deref; DW_OP_fbreg: -80; DW_OP_deref; DW_OP_mul)
Comment 1 Jan Kratochvil 2016-09-14 12:51:49 UTC
Created attachment 39617 [details]
dwarf-stridex.f90
Comment 2 Jakub Jelinek 2016-09-15 08:21:52 UTC
Broken with early debug merge r224161.
Comment 3 Jakub Jelinek 2016-09-15 09:01:48 UTC
I'm afraid this is similar to the DW_AT_string_length troubles (but not to the direct reference to a DIE of some local variable, which can be besides the hack we have now solved using DWARF extension, but to the indirect one where we only have the hack which won't really work for LTO).

In this case, when the FE fills in the array_descr_info, it fills in:
(gdb) p debug_generic_stmt (info->dimen[0].lower_bound)
*(D#1 + 32);

$4 = void
(gdb) p debug_generic_stmt (info->dimen[0].upper_bound)
*(D#1 + 40);

$5 = void
(gdb) p debug_generic_stmt (info->dimen[0].stride)
*(D#1 + 24) * span.0;

The first two are representable just fine,
        .uleb128 0x4    # DW_AT_lower_bound
        .byte   0x97    # DW_OP_push_object_address
        .byte   0x23    # DW_OP_plus_uconst
        .uleb128 0x20
        .byte   0x6     # DW_OP_deref
and
        .uleb128 0x4    # DW_AT_upper_bound
        .byte   0x97    # DW_OP_push_object_address
        .byte   0x23    # DW_OP_plus_uconst
        .uleb128 0x28
        .byte   0x6     # DW_OP_deref
but the problem is with the stride, it refers to a local variable, but obviously during early debug we don't really have location description for that variable.  And like for DW_AT_string_lenght, DW_OP_call{2,4,_ref} isn't the 100% answer here, because those expect the referenced DIE has DWARF expression rather than location description.  So we'd need DW_OP_variable_value or something similar.
Comment 4 rguenther@suse.de 2016-09-15 09:21:42 UTC
On Thu, 15 Sep 2016, jakub at gcc dot gnu.org wrote:

> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77589
> 
> Jakub Jelinek <jakub at gcc dot gnu.org> changed:
> 
>            What    |Removed                     |Added
> ----------------------------------------------------------------------------
>                  CC|                            |aldyh at gcc dot gnu.org,
>                    |                            |rguenth at gcc dot gnu.org
> 
> --- Comment #3 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
> I'm afraid this is similar to the DW_AT_string_length troubles (but not to the
> direct reference to a DIE of some local variable, which can be besides the hack
> we have now solved using DWARF extension, but to the indirect one where we only
> have the hack which won't really work for LTO).
> 
> In this case, when the FE fills in the array_descr_info, it fills in:
> (gdb) p debug_generic_stmt (info->dimen[0].lower_bound)
> *(D#1 + 32);
> 
> $4 = void
> (gdb) p debug_generic_stmt (info->dimen[0].upper_bound)
> *(D#1 + 40);
> 
> $5 = void
> (gdb) p debug_generic_stmt (info->dimen[0].stride)
> *(D#1 + 24) * span.0;
> 
> The first two are representable just fine,
>         .uleb128 0x4    # DW_AT_lower_bound
>         .byte   0x97    # DW_OP_push_object_address
>         .byte   0x23    # DW_OP_plus_uconst
>         .uleb128 0x20
>         .byte   0x6     # DW_OP_deref
> and
>         .uleb128 0x4    # DW_AT_upper_bound
>         .byte   0x97    # DW_OP_push_object_address
>         .byte   0x23    # DW_OP_plus_uconst
>         .uleb128 0x28
>         .byte   0x6     # DW_OP_deref
> but the problem is with the stride, it refers to a local variable, but
> obviously during early debug we don't really have location description for that
> variable.  And like for DW_AT_string_lenght, DW_OP_call{2,4,_ref} isn't the
> 100% answer here, because those expect the referenced DIE has DWARF expression
> rather than location description.  So we'd need DW_OP_variable_value or
> something similar.

So DW_OP_GNU_implicit_ptr doesn't work here?  Not sure
I understand how DW_OP_GNU_implicit_ptr works fully.  That is,

  ... *(D#1 + 24)
  DW_OP_GNU_implicit_ptr <span.0> + 0
  DW_OP_mul

the examples in the specification always finish the dwarf expression
with DW_OP_GNU_implicit_ptr which wouldn't be the case here.
Comment 5 Jakub Jelinek 2016-09-15 09:31:00 UTC
(In reply to rguenther@suse.de from comment #4)
> So DW_OP_GNU_implicit_ptr doesn't work here?  Not sure
> I understand how DW_OP_GNU_implicit_ptr works fully.  That is,
> 
>   ... *(D#1 + 24)
>   DW_OP_GNU_implicit_ptr <span.0> + 0
>   DW_OP_mul
> 
> the examples in the specification always finish the dwarf expression
> with DW_OP_GNU_implicit_ptr which wouldn't be the case here.

No, it doesn't, for 2 reasons:
1) DW_OP_implicit_ptr (DWARF5) / DW_OP_GNU_implicit_ptr (GNU) is a DWARF location description op, so can't appear in the middle of DWARF expression, but has to appear on its own; it has a bias argument, so you can say that
int a = 5;
char *b = ((char *) &a) + 2;
b has DW_AT_location DW_OP_GNU_implicit_ptr <a, 2>, but that is it; it is like DW_OP_reg* or DW_OP_stack_value that can't appear in the middle, and more like DW_OP_reg* which also has to appear on its own (or say combined through DW_OP_piece).
2) it doesn't give you the value, but the address of the referenced DIE.  So, if 1) wasn't a problem, you'd need ... DW_OP_implicit_ptr <span.0> DW_OP_deref DW_OP_mul to get the value and multiply.

I've proposed DW_OP_variable_value for this, will see if I get any feedback on that.
Comment 6 Jakub Jelinek 2017-02-08 16:55:45 UTC
Created attachment 40696 [details]
gcc7-pr77589.patch

Untested fix (introduces DW_OP_GNU_variable_value, something GDB/elfutils would need to implement too).
Comment 7 Jakub Jelinek 2017-02-25 08:18:56 UTC
Author: jakub
Date: Sat Feb 25 08:18:24 2017
New Revision: 245733

URL: https://gcc.gnu.org/viewcvs?rev=245733&root=gcc&view=rev
Log:
	PR debug/77589
include/
	* dwarf2.def (DW_OP_GNU_variable_value): New opcode.
gcc/
	* dwarf2out.c (struct dw_loc_list_struct): Add noted_variable_value
	bitfield.
	(size_of_loc_descr): Handle DW_OP_GNU_variable_value.
	(output_loc_operands): Handle DW_OP_call_ref and
	DW_OP_GNU_variable_value.
	(struct variable_value_struct): New type.
	(struct variable_value_hasher): Likewise.
	(variable_value_hash): New variable.
	(string_types): Remove.
	(copy_loc_descr): New function.
	(add_loc_descr_to_each): Clarify comment.  Use copy_loc_descr.
	(prepend_loc_descr_to_each): New function.
	(add_loc_list): Fix comment typo.  Use prepend_loc_descr_to_each
	instead of add_loc_descr_to_each if the first argument is single
	location list and the second has multiple.
	(resolve_args_picking_1): Handle DW_OP_GNU_variable_value.
	(loc_list_from_tree_1): For early_dwarf, emit DW_OP_GNU_variable_value
	when looking for variable value which doesn't have other location info.
	(loc_list_from_tree): Formatting fix.
	(gen_array_type_die): Simplify DW_AT_string_length handling.
	(adjust_string_types): Remove.
	(gen_subprogram_die): Don't call adjust_string_types nor test/set
	string_types.  Call resolve_variable_values.
	(prune_unused_types_walk_loc_descr): Handle DW_OP_GNU_variable_value.
	(resolve_addr_in_expr): Likewise.  Add A argument.
	(copy_deref_exprloc): Remove deref argument.  Adjust for the
	original expression being DW_OP_GNU_variable_value with optionally
	DW_OP_stack_value after it instead of DW_OP_call4 with DW_OP_deref
	optionally after it.
	(optimize_string_length): Rework for DW_OP_GNU_variable_value.
	(resolve_addr): Adjust optimize_string_length and resolve_addr_in_expr
	callers.  Set remove_AT_byte_size if removing DW_AT_string_length.
	(variable_value_hasher::hash, variable_value_hasher::equal): New
	methods.
	(resolve_variable_value_in_expr, resolve_variable_value,
	resolve_variable_values, note_variable_value_in_expr,
	note_variable_value): New functions.
	(dwarf2out_early_finish): Call note_variable_value on all toplevel
	DIEs.

Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/dwarf2out.c
    trunk/include/ChangeLog
    trunk/include/dwarf2.def
Comment 8 Jakub Jelinek 2017-02-25 08:30:17 UTC
Fixed for 7+ (assuming GDB will get DW_OP_GNU_variable_value support added soon).
No plans to backport this.
Comment 9 Tom de Vries 2018-07-31 10:00:50 UTC
(In reply to Jakub Jelinek from comment #8)
> Fixed for 7+ (assuming GDB will get DW_OP_GNU_variable_value support added
> soon).
> No plans to backport this.

It looks like we've stopped generating DW_OP_GNU_variable_value for this example at some point:
...
$ ( cc=gfortran; $cc --version; $cc -g test.f90 -save-temps -dA && grep variable_value test.s )
GNU Fortran (SUSE Linux) 7.3.1 20180323 [gcc-7-branch revision 258812]
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

        .byte   0xfd    # DW_OP_GNU_variable_value
$
$( cc=./install/bin/gfortran; $cc --version; $cc -g test.f90 -save-temps -dA && grep variable_value test.s )
GNU Fortran (GCC) 9.0.0 20180717 (experimental)
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$
...
Comment 10 Jakub Jelinek 2018-07-31 10:13:02 UTC
Yes, since r251949, because gfortran changed ABI.
That doesn't mean DW_OP_GNU_variable_value isn't emitted in other cases, and AFAIK Kevin Buettner has the GDB support for it pretty much written but not yet submitted.
Comment 11 Tom de Vries 2018-07-31 15:01:54 UTC
(In reply to Jakub Jelinek from comment #10)
> AFAIK Kevin Buettner has the GDB support for it pretty much written but not
> yet submitted.

Mentioned this at https://sourceware.org/bugzilla/show_bug.cgi?id=22399#c1