https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94474
Bug ID: 94474 Summary: Incorrect DWARF range information for inlined function Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: debug Assignee: unassigned at gcc dot gnu.org Reporter: andrew.burgess at embecosm dot com Target Milestone: --- Created attachment 48190 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=48190&action=edit Bug reproducer. Download the attached file, then: tar -xf gcc-ranges-bugs.tar.xz cd gcc-ranges-bugs make The problem is described in the included README file, the contents of which I will include below. -- * Overview + The issues are present in all compilations, but v3 uses what I think might be the "best" debug flags. + Tested on GCC 9.2.0 and GCC from master branch (2020-02-05). + These bugs were encountered when trying to improve is-stmt support within GDB. + This bug report has a bit of history. Originally there was a GCC patch here: https://gcc.gnu.org/ml/gcc-patches/2019-10/msg01459.html and a reply here: https://gcc.gnu.org/ml/gcc-patches/2019-10/msg01459.html This led to a GDB patch here: https://gcc.gnu.org/ml/gcc-patches/2019-10/msg01459.html which in turn led to a different GDB patch (adding is-stmt support), here: https://gcc.gnu.org/ml/gcc-patches/2019-10/msg01459.html + As suggested in the 2019-10 GCC follow up, I have tried compiling with =-gno-statement-frontiers -gno-variable-location-views=, and currently the debug experience is better, but if I hack GDB to "fix" the bugs below while reading in the DWARF then I get just as good a debug experience with GCC's default flags. + In the included Makefile I build the test 4 times, version 3 is possibly the most interesting, as this explicitly switches on what I think are the "best" features for location tracking. However, the same bugs are present in v1 and v2 (see Makefile for flag differences). Version 4 compiles with the =-gno-*= flags above, and is included for reference. As I've already said, these bugs are not present there. + All of the analysis below references the output files =test-v3=, =dissas-v3=, =dwarf-v3=, and =lines-v3=. * Issue 1 + The function =tree_check= is inlined 3 times. + The first =DW_TAG_inlined_subroutine= looks like this: #+BEGIN_EXAMPLE <2><8db>: Abbrev Number: 38 (DW_TAG_inlined_subroutine) <8dc> DW_AT_abstract_origin: <0x9cc> <8e0> DW_AT_entry_pc : 0x400545 <8e8> Unknown AT value: 2138: 3 <8e9> DW_AT_ranges : 0x30 <8ed> DW_AT_call_file : 1 <8ee> DW_AT_call_line : 52 <8ef> DW_AT_call_column : 10 <8f0> DW_AT_sibling : <0x92f> #+END_EXAMPLE This references some =.debug_ranges= data that looks like this: #+BEGIN_EXAMPLE 00000030 0000000000400545 0000000000400545 (start == end) 00000030 0000000000400549 0000000000400553 00000030 0000000000400430 0000000000400435 00000030 <End of list> #+END_EXAMPLE + Notice that =0x400545= is /not/ part of the range for the inlined function as the range ==0x400545= to =0x400545= is an empty range, containing no bytes (see DWARF-4, 2.17.3: Non-Contiguous Address Ranges). + The =DW_AT_entry_pc= points to =0x400545=. + DWARF-4, 2.18: Entry Address, says: #+BEGIN_QUOTE Any debugging information entry describing an entity that has a range of code addresses, which includes compilation units, module initialization, subroutines, ordinary blocks, try/catch blocks, and the like, may have a DW_AT_entry_pc attribute to indicate the first executable instruction within that range of addresses. #+END_QUOTE I believe this means that the =DW_AT_entry_pc= should reference an address that is within the range of addresses associated with the inlined subroutine. + The particular problem this causes for GDB is that the decoded line table (see =lines-v3=) includes: #+BEGIN_EXAMPLE ./step-and-next-inline.h:[++] step-and-next-inline.h 32 0x400545 3 x step-and-next-inline.h 34 0x400545 4 x #+END_EXAMPLE GDB then stops for these lines (that are part of the inlined function, at an address that is not part of the inlined functions address range. + An idea solution for GDB would be to include the address =0x400545= within the address range of the inlined function, and when I earlier said I hacked GDB to "fix" this bug, this is what I did, extending the range entry starting at =0x400549= to instead start at =0x400545=. * Issue 2 + Looking at the other end of the range now, there's a range =0x400549= to =0x400553=, again according to 'DWARF-4, 2.17.3: Non-Contiguous Address Ranges' anything at =0x400553= is not within this range. + Looking at the decoded line table (see =lines-v3=) we see this: #+BEGIN_EXAMPLE ./step-and-next-inline.h:[++] step-and-next-inline.h 32 0x400545 3 x step-and-next-inline.h 34 0x400545 4 x ./step-and-next-inline.cc:[++] step-and-next-inline.cc 50 0x400545 5 ./step-and-next-inline.h:[++] step-and-next-inline.h 34 0x400549 6 step-and-next-inline.h 34 0x40054b 7 step-and-next-inline.h 36 0x400553 8 x step-and-next-inline.h 37 0x400553 9 x step-and-next-inline.h 37 0x400553 10 ./step-and-next-inline.cc:[++] step-and-next-inline.cc 52 0x400553 11 step-and-next-inline.cc 52 0x400556 12 #+END_EXAMPLE + Notice that lines 36 and 37 of step-and-next-inline.h are listed (with is-stmt = true) as being at =0x400553=. This is upsets GDB quite a bit as stopping at these addresses reports a line from the inilned function, but, as this is outside of the range associated with the inlined function, GDB doesn't understand that we are in the inlined frame. + This miss-placing of lines 36 and 37 is repeated for all three inlined instances. + I think the ideal solution for GDB would be to include that address within the range, or if that's not possible, or not appropriate, don't have those lines marked as 'is-stmt = true', then at least GDB would not try to stop their. When I said earlier I hacked GDB to "fix" this issue, this is what I did, I extended the upper bound for all three inline functions by 3 bytes (to cover one more instruction).