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)
Created attachment 39617 [details] dwarf-stridex.f90
Broken with early debug merge r224161.
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.
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.
(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.
Created attachment 40696 [details] gcc7-pr77589.patch Untested fix (introduces DW_OP_GNU_variable_value, something GDB/elfutils would need to implement too).
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
Fixed for 7+ (assuming GDB will get DW_OP_GNU_variable_value support added soon). No plans to backport this.
(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. $ ...
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.
(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