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).