public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug debug/94474] New: Incorrect DWARF range information for inlined function
@ 2020-04-03 16:13 andrew.burgess at embecosm dot com
  2020-04-06  9:59 ` [Bug debug/94474] " bernd.edlinger at hotmail dot de
                   ` (14 more replies)
  0 siblings, 15 replies; 16+ messages in thread
From: andrew.burgess at embecosm dot com @ 2020-04-03 16:13 UTC (permalink / raw)
  To: gcc-bugs

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

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [Bug debug/94474] Incorrect DWARF range information for inlined function
  2020-04-03 16:13 [Bug debug/94474] New: Incorrect DWARF range information for inlined function andrew.burgess at embecosm dot com
@ 2020-04-06  9:59 ` bernd.edlinger at hotmail dot de
  2020-04-06 10:54 ` andrew.burgess at embecosm dot com
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: bernd.edlinger at hotmail dot de @ 2020-04-06  9:59 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94474

--- Comment #1 from Bernd Edlinger <bernd.edlinger at hotmail dot de> ---
Hi,

I use a newer binutils versions FWIW, and buit GCC-10 from
a few days ago using those binutils.

$ readelf -version
GNU readelf (GNU Binutils) 2.32
Copyright (C) 2019 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or (at your option) any later version.
This program has absolutely no warranty.

instead of
    #+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

 I see:

 <2><8b3>: Abbrev Number: 38 (DW_TAG_inlined_subroutine)
    <8b4>   DW_AT_abstract_origin: <0x9a4>
    <8b8>   DW_AT_entry_pc    : 0x401165
    <8c0>   DW_AT_GNU_entry_view: 0
    <8c1>   DW_AT_ranges      : 0x30
    <8c5>   DW_AT_call_file   : 1
    <8c6>   DW_AT_call_line   : 52
    <8c7>   DW_AT_call_column : 10
    <8c8>   DW_AT_sibling     : <0x907>

But as you can see there is a view number where
the range begins, but there is no view number where
the range ends.

I am not sure if there are any view numbers when
the inline has multiple ranges, (I dont remember)

Therefore I try to chamge gdb to ignore is-stmt breakpoints
which are at the end of the inline block.

I am not sure if an entirely new DWARF version is necessary,
or just a new  AT value: like 2139 or so, to give us
an idea if the is-stmt is per its view in the subroutine
or in the calling program.


Bernd.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [Bug debug/94474] Incorrect DWARF range information for inlined function
  2020-04-03 16:13 [Bug debug/94474] New: Incorrect DWARF range information for inlined function andrew.burgess at embecosm dot com
  2020-04-06  9:59 ` [Bug debug/94474] " bernd.edlinger at hotmail dot de
@ 2020-04-06 10:54 ` andrew.burgess at embecosm dot com
  2020-04-06 11:04 ` bernd.edlinger at hotmail dot de
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: andrew.burgess at embecosm dot com @ 2020-04-06 10:54 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94474

--- Comment #2 from Andrew Burgess <andrew.burgess at embecosm dot com> ---
Sorry for including the wrong DWARF dump output in the bug report.  I too had
seen the DW_AT_GNU_entry_view using a more recent binutils.

When you pose the question:

  I am not sure if there are any view numbers when the inline has multiple
ranges, (I dont remember)

I think you're asking do we get DW_AT_GNU_entry_view when we have multiple
ranges.  And the answer is yes, this case already has multiple ranges (it has a
DW_AT_ranges, which contains multiple ranges), and this is super confusing,
because each range could, I guess, could have a different view number for its
start, right?

It seems that, when a debug entity has a single range defined within the entity
then we need a start and end view number.

When a debug entity makes use of separate range information, each range will
need its own start and end view number.

If the above requires new DWARF extensions, then GCC might just decide to try
and make the best with the version of DWARF it currently has available.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [Bug debug/94474] Incorrect DWARF range information for inlined function
  2020-04-03 16:13 [Bug debug/94474] New: Incorrect DWARF range information for inlined function andrew.burgess at embecosm dot com
  2020-04-06  9:59 ` [Bug debug/94474] " bernd.edlinger at hotmail dot de
  2020-04-06 10:54 ` andrew.burgess at embecosm dot com
@ 2020-04-06 11:04 ` bernd.edlinger at hotmail dot de
  2020-04-06 11:17 ` bernd.edlinger at hotmail dot de
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: bernd.edlinger at hotmail dot de @ 2020-04-06 11:04 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94474

--- Comment #3 from Bernd Edlinger <bernd.edlinger at hotmail dot de> ---
(In reply to Andrew Burgess from comment #2)
> Sorry for including the wrong DWARF dump output in the bug report.  I too
> had seen the DW_AT_GNU_entry_view using a more recent binutils.
> 

NP.

> When you pose the question:
> 
>   I am not sure if there are any view numbers when the inline has multiple
> ranges, (I dont remember)
> 
> I think you're asking do we get DW_AT_GNU_entry_view when we have multiple
> ranges.  And the answer is yes, this case already has multiple ranges (it
> has a DW_AT_ranges, which contains multiple ranges), and this is super
> confusing, because each range could, I guess, could have a different view
> number for its start, right?
> 

I am talking about the end of the range each of the subranges
They should have view numbers, gdb should note the view number
when parsing the line program.

I think we need an DW_AT_GNU_exit_view, you know, young jedi :-)


Bernd.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [Bug debug/94474] Incorrect DWARF range information for inlined function
  2020-04-03 16:13 [Bug debug/94474] New: Incorrect DWARF range information for inlined function andrew.burgess at embecosm dot com
                   ` (2 preceding siblings ...)
  2020-04-06 11:04 ` bernd.edlinger at hotmail dot de
@ 2020-04-06 11:17 ` bernd.edlinger at hotmail dot de
  2020-04-06 12:55 ` andrew.burgess at embecosm dot com
                   ` (10 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: bernd.edlinger at hotmail dot de @ 2020-04-06 11:17 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94474

--- Comment #4 from Bernd Edlinger <bernd.edlinger at hotmail dot de> ---
Can you please approve my patch now?

https://sourceware.org/pipermail/gdb-patches/2020-April/167385.html

Thanks
Bernd.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [Bug debug/94474] Incorrect DWARF range information for inlined function
  2020-04-03 16:13 [Bug debug/94474] New: Incorrect DWARF range information for inlined function andrew.burgess at embecosm dot com
                   ` (3 preceding siblings ...)
  2020-04-06 11:17 ` bernd.edlinger at hotmail dot de
@ 2020-04-06 12:55 ` andrew.burgess at embecosm dot com
  2020-04-06 12:57 ` bernd.edlinger at hotmail dot de
                   ` (9 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: andrew.burgess at embecosm dot com @ 2020-04-06 12:55 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94474

--- Comment #5 from Andrew Burgess <andrew.burgess at embecosm dot com> ---
Bernd, 

Wouldn't DW_AT_GNU_exit_view be attached to the DW_TAG_inlined_subroutine
though?  

So, as in this case, one subroutine has 2 ranges, but would then have one end
view number.

I don't understand why each range wouldn't need its own view number?

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [Bug debug/94474] Incorrect DWARF range information for inlined function
  2020-04-03 16:13 [Bug debug/94474] New: Incorrect DWARF range information for inlined function andrew.burgess at embecosm dot com
                   ` (4 preceding siblings ...)
  2020-04-06 12:55 ` andrew.burgess at embecosm dot com
@ 2020-04-06 12:57 ` bernd.edlinger at hotmail dot de
  2020-04-06 13:15 ` bernd.edlinger at hotmail dot de
                   ` (8 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: bernd.edlinger at hotmail dot de @ 2020-04-06 12:57 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94474

--- Comment #6 from Bernd Edlinger <bernd.edlinger at hotmail dot de> ---
Right,

    #+BEGIN_EXAMPLE
      00000030 0000000000400545 0000000000400545 (start == end)
      00000030 0000000000400549 0000000000400553
      00000030 0000000000400430 0000000000400435
      00000030 <End of list>
    #+END_EXAMPLE

I dont see any view numbers here, but I would need them.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [Bug debug/94474] Incorrect DWARF range information for inlined function
  2020-04-03 16:13 [Bug debug/94474] New: Incorrect DWARF range information for inlined function andrew.burgess at embecosm dot com
                   ` (5 preceding siblings ...)
  2020-04-06 12:57 ` bernd.edlinger at hotmail dot de
@ 2020-04-06 13:15 ` bernd.edlinger at hotmail dot de
  2020-04-06 14:16 ` andrew.burgess at embecosm dot com
                   ` (7 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: bernd.edlinger at hotmail dot de @ 2020-04-06 13:15 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94474

--- Comment #7 from Bernd Edlinger <bernd.edlinger at hotmail dot de> ---
> I don't understand why each range wouldn't need its own view number?

Each of the sub ranges end PC can be an exit point.
At least how I see it.

Please have a look at my patch.

It adds each of the ranges end address to the
end address list, and there are two cases,
one where only one range is there, and
one where multiple ranges are there.

then the end PC addresses are used to modify the
is-stmt bits of the corresponding line entries if there are any.

Those cannot be used for break points per line number, possibly.
But I dont care.

Thanks
Bernd.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [Bug debug/94474] Incorrect DWARF range information for inlined function
  2020-04-03 16:13 [Bug debug/94474] New: Incorrect DWARF range information for inlined function andrew.burgess at embecosm dot com
                   ` (6 preceding siblings ...)
  2020-04-06 13:15 ` bernd.edlinger at hotmail dot de
@ 2020-04-06 14:16 ` andrew.burgess at embecosm dot com
  2020-04-28  2:17 ` bernd.edlinger at hotmail dot de
                   ` (6 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: andrew.burgess at embecosm dot com @ 2020-04-06 14:16 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94474

--- Comment #8 from Andrew Burgess <andrew.burgess at embecosm dot com> ---
Bernd, 

Please could you keep discussion of GDB patches to the GDB mailing list unless
it is required to move this bug forward.

In this bug I make the claim that the DWARF GCC produces is not correct.  So
far I don't think you are disagreeing with that.

You are, I think, proposing that we should add range end view numbers to the
range table.  I'm not disagreeing that this would solve the problem.

However,

Right now I don't think such a feature is currently in the DWARF standard,
maybe it exists as part of a DWARF proposal?  Or maybe as a GCC extension?  I
don't know.

The question I'm asking to the wider GCC community would be, given the (I
claim) current incorrect DWARF, should GCC be changed to produce something
better using existing standard DWARF?  Should a new GCC DWARF extension be
invented?

I certainly don't claim to have the answer here, but hopefully someone else
might have a concrete proposal.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [Bug debug/94474] Incorrect DWARF range information for inlined function
  2020-04-03 16:13 [Bug debug/94474] New: Incorrect DWARF range information for inlined function andrew.burgess at embecosm dot com
                   ` (7 preceding siblings ...)
  2020-04-06 14:16 ` andrew.burgess at embecosm dot com
@ 2020-04-28  2:17 ` bernd.edlinger at hotmail dot de
  2020-04-28  9:56 ` andrew.burgess at embecosm dot com
                   ` (5 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: bernd.edlinger at hotmail dot de @ 2020-04-28  2:17 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94474

--- Comment #9 from Bernd Edlinger <bernd.edlinger at hotmail dot de> ---
Andrew,

please update the reproducer, and explain in more detail
what you would like to be changed.

I still do not understand your idea.
But I try hard to do so.


Please be patient with me.

Bernd.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [Bug debug/94474] Incorrect DWARF range information for inlined function
  2020-04-03 16:13 [Bug debug/94474] New: Incorrect DWARF range information for inlined function andrew.burgess at embecosm dot com
                   ` (8 preceding siblings ...)
  2020-04-28  2:17 ` bernd.edlinger at hotmail dot de
@ 2020-04-28  9:56 ` andrew.burgess at embecosm dot com
  2020-05-16  8:09 ` bernd.edlinger at hotmail dot de
                   ` (4 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: andrew.burgess at embecosm dot com @ 2020-04-28  9:56 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94474

--- Comment #10 from Andrew Burgess <andrew.burgess at embecosm dot com> ---
Bernd,

Not a problem, always happy to expand on things.  This might get a
little long, but hopefully it should give you an idea what I think is
wrong.

I have not updated the reproducer, I don't know why I would need to do
that, as the existing example demonstrates the issues.  My original
comment did use an older version of binutils though, which is why I
saw =<8e8>   Unknown AT value: 2138: 3=, which was unfortunate.  I'm now
using binutils 2.34.

To reduce the length of this post I'm only looking at the first
inlined subroutine, this is the worst offender, the issues with the
other two are just repeats of this one.

>From the reproducer I'm only looking at the *-v3 output files.

Here's the DWARF for the first inlined subroutine:

#+BEGIN_EXAMPLE
   <2><8dd>: Abbrev Number: 38 (DW_TAG_inlined_subroutine)
      <8de>   DW_AT_abstract_origin: <0x9ce>
      <8e2>   DW_AT_entry_pc    : 0x401165
      <8ea>   DW_AT_GNU_entry_view: 0
      <8eb>   DW_AT_ranges      : 0x30
      <8ef>   DW_AT_call_file   : 1
      <8f0>   DW_AT_call_line   : 52
      <8f1>   DW_AT_call_column : 10
      <8f2>   DW_AT_sibling     : <0x931>
#+END_EXAMPLE

It references the range information at offset 0x30, which can be seen
here, the duplication is just an objdump oddity, the ranges we care
about are the first four lines starting with =00000030=:

#+BEGIN_EXAMPLE
  Contents of the .debug_ranges section:

      Offset   Begin    End
      00000000 0000000000401160 00000000004011ca
      00000000 0000000000401040 0000000000401045
      00000000 <End of list>
      00000030 0000000000401165 0000000000401165 (start == end)
      00000030 0000000000401169 0000000000401173
      00000030 0000000000401040 0000000000401045
      00000030 <End of list>
      00000030 0000000000401165 0000000000401165 (start == end)
      00000030 0000000000401169 0000000000401173
      00000030 0000000000401040 0000000000401045
      00000030 <End of list>
      00000070 0000000000401160 00000000004011ca
      00000070 0000000000401040 0000000000401045
      00000070 0000000000401050 0000000000401065
      00000070 <End of list>
#+END_EXAMPLE

Next, here's a snippet of disassembler, this covers two of the ranges
from the above, the empty one =0x401165= to =0x401165=, and then =0x401169=
to =0x401173=.  The range =0x401040= to =0x401045= I'm ignoring for now,
it's just some out of line cold code and not important for this
discussion:

#+BEGIN_EXAMPLE
  0000000000401160 <_Z13get_alias_setP4tree>:
    401160:       48 85 ff                test   %rdi,%rdi
    401163:       74 4b                   je     4011b0
<_Z13get_alias_setP4tree+0x50>
    401165:       48 83 ec 08             sub    $0x8,%rsp
    401169:       8b 07                   mov    (%rdi),%eax
    40116b:       85 c0                   test   %eax,%eax
    40116d:       0f 85 cd fe ff ff       jne    401040
<_Z13get_alias_setP4tree.cold>
    401173:       8b 47 04                mov    0x4(%rdi),%eax
    401176:       83 f8 01                cmp    $0x1,%eax
    401179:       74 28                   je     4011a3
<_Z13get_alias_setP4tree+0x43>
    40117b:       8b 07                   mov    (%rdi),%eax
    40117d:       85 c0                   test   %eax,%eax
#+END_EXAMPLE

Finally, a snippet of the line table covering the same disassembler
region as above:

#+BEGIN_EXAMPLE
  test-v3:     file format elf64-x86-64

  Contents of the .debug_line section:

  CU: ./step-and-next-inline.cc:
  File name                            Line number    Starting address    View 
  Stmt
  step-and-next-inline.cc                       50            0x401160         
     x
  step-and-next-inline.cc                       51            0x401160       1 
     x
  step-and-next-inline.cc                       54            0x401160       2

  ./step-and-next-inline.h:[++]
  step-and-next-inline.h                        32            0x401165         
     x
  step-and-next-inline.h                        34            0x401165       1 
     x

  ./step-and-next-inline.cc:[++]
  step-and-next-inline.cc                       50            0x401165       2

  ./step-and-next-inline.h:[++]
  step-and-next-inline.h                        34            0x401169
  step-and-next-inline.h                        34            0x40116b
  step-and-next-inline.h                        36            0x401173         
     x
  step-and-next-inline.h                        37            0x401173       1 
     x
  step-and-next-inline.h                        37            0x401173       2

  ./step-and-next-inline.cc:[++]
  step-and-next-inline.cc                       52            0x401173       3
  step-and-next-inline.cc                       52            0x401176
#+END_EXAMPLE

Here is what I think GCC could have produced for the range
information instead:

#+BEGIN_EXAMPLE
      00000030 0000000000401165 0000000000401176
      00000030 0000000000401040 0000000000401045
      00000030 <End of list>
#+END_EXAMPLE

The changes are:

 (1) The empty range at =0x401165= is now folded into the following
     range, which coincidentally started at the very next instruction
     anyway.

 (2) The range previously ending at =0x401173= now ends at =0x401176=,
     extending by one instruction.

The reasoning is that:

 (1) The DW_AT_entry_pc is now within a range attributed to the
 inlined subroutine.

 (2) All lines marked as is-stmt for the subroutine, are within a
 range attributed to the subroutine.  A debugger stopping at one of
 those lines will now understand that:
     (a) It is at a particular line, and
     (b) It is within a particular subroutine.
 Notice that at =0x401173= we have lines from both the inlined
 subroutine, and from the enclosing calller function.  However, it is
 the inlined callee that is marked is-stmt for this address, I believe
 this should mean this address is included in the range for the
 inlined subroutine.

While I'm writing this I want to take a moment to address views.  I'm
still reading and learning about views, but I think they are relevant
here.

Non of the proposed view specifications I have yet seen go far enough
to address applying the views technique to ranges.  Each range could
potentially be improved by having an entry and exit view.  When a
DW_TAG_inlined_subroutine references an external ranges list, then
each sub-range in that list needs to be able to have its own entry and
exit view.  Currently, in the example above we have one
DW_AT_GNU_entry_view for 3 ranges (though one is empty and can be
ignored).  Without some really clever engineering, one entry view is
never going to be correct for multiple sub-ranges.

Further, I've seen no mention of exit views anywhere, and I think they
would also be needed.

With the addition of these two features we would be able to support (I
believe) fully merged callers and callees, with lines marked as
is-stmt from both the caller and callee appearing at the same address.

For now, without this, I think GCC needs to restrict itself when
inlining.  When an address represents a line from both the caller and
callee, then that address should only be is-stmt true for EITHER lines
from the caller, or lines from the callee.  If the address is is-stmt
true for a line from the caller, then the address should NOT be within
the callee's range(s), and if the address is is-stmt true for a line
from the callee, then the address MUST be within the callee's
range(s).

On a final note.  These are just my personal thoughts from the
perspective of a debug consumer, though I use words like "must" or
"should" above this reflects my thoughts on how I believe the debug
should appear, and is not an attempt to prescribe how GCC should
be.  I know there are limitations to what GCC can achieve, and also, I
could be totally wrong in my understanding of DWARF.  I'm always happy
to be corrected!

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [Bug debug/94474] Incorrect DWARF range information for inlined function
  2020-04-03 16:13 [Bug debug/94474] New: Incorrect DWARF range information for inlined function andrew.burgess at embecosm dot com
                   ` (9 preceding siblings ...)
  2020-04-28  9:56 ` andrew.burgess at embecosm dot com
@ 2020-05-16  8:09 ` bernd.edlinger at hotmail dot de
  2020-05-17  8:43 ` andrew.burgess at embecosm dot com
                   ` (3 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: bernd.edlinger at hotmail dot de @ 2020-05-16  8:09 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94474

--- Comment #11 from Bernd Edlinger <bernd.edlinger at hotmail dot de> ---
Andrew,

(In reply to Andrew Burgess from comment #10)
> Further, I've seen no mention of exit views anywhere, and I think they
> would also be needed.
> 

Yes, that is also my idea, when I say the dwarf2 spec needs to
be fixed.

> With the addition of these two features we would be able to support (I
> believe) fully merged callers and callees, with lines marked as
> is-stmt from both the caller and callee appearing at the same address.
> 
> For now, without this, I think GCC needs to restrict itself when
> inlining.  When an address represents a line from both the caller and
> callee, then that address should only be is-stmt true for EITHER lines
> from the caller, or lines from the callee.  If the address is is-stmt
> true for a line from the caller, then the address should NOT be within
> the callee's range(s), and if the address is is-stmt true for a line
> from the callee, then the address MUST be within the callee's
> range(s).
> 

I tried to do something similar, in my original gcc-patch,
which was unfortunately not accepted.

But what I learned from writing the patch is that gcc cannot
easily tell if a range will be empty or not.  That is because
the assembler does emit the line info and the views,
and the assembler decides how many bytes if any a certain
construct will take in the binary representation.

That is why this empty range appears, because that was
supposed to be the start of the inline function, but
instructions from the function prologue were moved in there.
What causes the problem is the is-stmt line info which
is the only remaining thing from the original plan.
But on the other hand, it is not a big issue for gdb to
ignore those artefacts, when they rarely occur.
My gdb-patch does this, by changing the is-stmt bit of
this line info.

> On a final note.  These are just my personal thoughts from the
> perspective of a debug consumer, though I use words like "must" or
> "should" above this reflects my thoughts on how I believe the debug
> should appear, and is not an attempt to prescribe how GCC should
> be.  I know there are limitations to what GCC can achieve, and also, I
> could be totally wrong in my understanding of DWARF.  I'm always happy
> to be corrected!

Yeah, that is true for myself as well.

Ping, Alexandre Oliva, are you still with us?
I would be curious to know what you think, about this how
should we proceed?


Thanks
Bernd.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [Bug debug/94474] Incorrect DWARF range information for inlined function
  2020-04-03 16:13 [Bug debug/94474] New: Incorrect DWARF range information for inlined function andrew.burgess at embecosm dot com
                   ` (10 preceding siblings ...)
  2020-05-16  8:09 ` bernd.edlinger at hotmail dot de
@ 2020-05-17  8:43 ` andrew.burgess at embecosm dot com
  2020-05-17  9:05 ` bernd.edlinger at hotmail dot de
                   ` (2 subsequent siblings)
  14 siblings, 0 replies; 16+ messages in thread
From: andrew.burgess at embecosm dot com @ 2020-05-17  8:43 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94474

--- Comment #12 from Andrew Burgess <andrew.burgess at embecosm dot com> ---
> But what I learned from writing the patch is that gcc cannot
> easily tell if a range will be empty or not.  That is because
> the assembler does emit the line info and the views,
> and the assembler decides how many bytes if any a certain
> construct will take in the binary representation.
>
> That is why this empty range appears, because that was
> supposed to be the start of the inline function, but
> instructions from the function prologue were moved in there.

I think there's some miss-communication here.  In the first paragraph
you say the assembler is responsible for deciding the binary
representation.  I'd agree with that, in the GNU toolchain this is
gas.

Then in the second paragraph you say the assembler is performing
instruction reordering.  Now I don't know every gas optimisation, so
I'm not saying gas doesn't do that, but it's not common, and it
certainly isn't what's happening in this case.  The instruction motion
is entirely within GCC.  I'll offer evidence for this below.

> What causes the problem is the is-stmt line info which
> is the only remaining thing from the original plan.

And here in lies the GCC bug (or one of them).  GCC has performed
instruction motion, and GCC has left behind its marker for the is-stmt
line.

I make no claim about how easy this is to fix, or if (given GCC's code
base) its even reasonably possible to consider fixing it, but that
doesn't mean it isn't a GCC issue.

> But on the other hand, it is not a big issue for gdb to
> ignore those artefacts, when they rarely occur.

GDB already ignores empty ranges.  The DWARF standard specifically
allows empty ranges and states that they are to be ignored.

But that isn't the artefact you're talking about, you mean the is-stmt
markers.

The problem is, the markers are placed at an address, given that every
address eventually contains an instruction[1] eventually, how can GDB
tell if one marker was left by accident or not?

> My gdb-patch does this, by changing the is-stmt bit of
> this line info.

Yes, and I think with this discussion we are getting closer to
understanding the work around you want to introduce to GDB, something
along the lines of:

  - On versions XXX -> YYY of GCC,
  - An is-stmt true marker,
  - At the same address as an empty range, that is
  - Associated with an inline function instance, should
  - Be ignored.

It's this kind of specific identification of the bug you're working
around that (for me at least) is holding back your GDB patch.

But, we shouldn't make a choice between work around the GCC bug in GDB
_or_ fix the bug in GCC.  The ideal solution (for me) would be, fix GCC
_and_ add a work around into GDB targeting the known broken versions
of GCC, then we get the best of both worlds.

---

To back up my claim that this is a GCC issue, you can generate the
assembler file test-v3.s from the reproducer.  The .debug_ranges looks
like this:

         .section        .debug_ranges,"",@progbits
  .Ldebug_ranges0:
          .quad   .LFB21
          .quad   .LHOTE0
          .quad   .LFSB21
          .quad   .LCOLDE0
          .quad   0
          .quad   0
          .quad   .LBB8
          .quad   .LBE8
          .quad   .LBB12
          .quad   .LBE12
          .quad   .LBB17
          .quad   .LBE17
          .quad   0
          .quad   0

The empty range is the first range in the second sequence, so this
one:

          .quad   .LBB8
          .quad   .LBE8

If we then find this in the assembler we see:

  .LBB8:
  .LBI8:
          .file 2 "step-and-next-inline.h"
          .loc 2 32 1 is_stmt 1 view .LVU3
  .LBB9:
          .loc 2 34 3 view .LVU4
  .LBE9:
  .LBE8:
          .loc 1 50 1 is_stmt 0 view .LVU5
          subq    $8, %rsp
          .cfi_def_cfa_offset 16

Notice, no assembler instructions (but there are assembler directives)
between LBB8 and LBE8.

I agree 100% with your diagnosis that this is likely due to
instruction reordering, but I disagree with your analysis that this is
done in the assembler and that therefore GCC has no visibility of
this.

---

[1] I know, not _literally_ every address, but you get the point.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [Bug debug/94474] Incorrect DWARF range information for inlined function
  2020-04-03 16:13 [Bug debug/94474] New: Incorrect DWARF range information for inlined function andrew.burgess at embecosm dot com
                   ` (11 preceding siblings ...)
  2020-05-17  8:43 ` andrew.burgess at embecosm dot com
@ 2020-05-17  9:05 ` bernd.edlinger at hotmail dot de
  2021-12-28 13:16 ` bernd.edlinger at hotmail dot de
  2021-12-28 20:57 ` bernd.edlinger at hotmail dot de
  14 siblings, 0 replies; 16+ messages in thread
From: bernd.edlinger at hotmail dot de @ 2020-05-17  9:05 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94474

--- Comment #13 from Bernd Edlinger <bernd.edlinger at hotmail dot de> ---
Hi Andrew,

You are right about the instruction re-ordering, that is done in
a compiler pass, which simply re-orders RTL instruction lists.
But I think when the code motion happens, we just
have no easy access to the range markers.
And it may be the case that this is-stmt location
mentions a register value that is indeed the parameter
of the inline function, so it may be no instruction but only
a side note, to the debugger, that a certain value would
be already here available in a certain register.
Also that is only a vague guess, since although I did already
a number of gcc patches, I learn new things each time :-)


Bernd.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [Bug debug/94474] Incorrect DWARF range information for inlined function
  2020-04-03 16:13 [Bug debug/94474] New: Incorrect DWARF range information for inlined function andrew.burgess at embecosm dot com
                   ` (12 preceding siblings ...)
  2020-05-17  9:05 ` bernd.edlinger at hotmail dot de
@ 2021-12-28 13:16 ` bernd.edlinger at hotmail dot de
  2021-12-28 20:57 ` bernd.edlinger at hotmail dot de
  14 siblings, 0 replies; 16+ messages in thread
From: bernd.edlinger at hotmail dot de @ 2021-12-28 13:16 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94474

--- Comment #14 from Bernd Edlinger <bernd.edlinger at hotmail dot de> ---
(In reply to Andrew Burgess from comment #0)
>   + 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
> 

one correction here:
the reply to the oct 2019 patch was here:
https://gcc.gnu.org/legacy-ml/gcc-patches/2019-11/msg01771.html

The follow up GDB patch probably this one is meant:
https://sourceware.org/pipermail/gdb-patches/2019-November/162747.html

The different patch adding is-stmt probably this one is meant:
https://sourceware.org/pipermail/gdb-patches/2019-December/164224.html

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [Bug debug/94474] Incorrect DWARF range information for inlined function
  2020-04-03 16:13 [Bug debug/94474] New: Incorrect DWARF range information for inlined function andrew.burgess at embecosm dot com
                   ` (13 preceding siblings ...)
  2021-12-28 13:16 ` bernd.edlinger at hotmail dot de
@ 2021-12-28 20:57 ` bernd.edlinger at hotmail dot de
  14 siblings, 0 replies; 16+ messages in thread
From: bernd.edlinger at hotmail dot de @ 2021-12-28 20:57 UTC (permalink / raw)
  To: gcc-bugs

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94474

--- Comment #15 from Bernd Edlinger <bernd.edlinger at hotmail dot de> ---
While there are certainly empty subranges that could be avoided,
there are also completely empty subroutines, which cannot be
avoided without losing the ability to inspect the procedure
variable at this location.  I have one example of that class here:

$ cat empty-inline.cc
/* This testcase is part of GDB, the GNU debugger.

   Copyright 2021 Free Software Foundation, Inc.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

/* PR 25987 */
struct MyClass;
struct ptr {
    MyClass* get() { return t; }     /* line 21 */
    MyClass* t;
};
struct MyClass { void call(); };
void MyClass::call() {
    *(volatile char*)(nullptr) = 1;  /* line 26 */
}
static void intermediate(ptr p) {
    p.get()->call();                 /* line 29 */
}
int main() {
    intermediate(ptr{new MyClass});
}
/* EOF */

$ gcc -g -Og empty-inline.cc

The empty inline I mean is ptr::get():

In the debug info this function looks like this:
 <2><11b>: Abbrev Number: 17 (DW_TAG_inlined_subroutine)
    <11c>   DW_AT_abstract_origin: <0x189>
    <120>   DW_AT_entry_pc    : 0x40113f
    <128>   DW_AT_GNU_entry_view: 2
    <129>   DW_AT_low_pc      : 0x40113f
    <131>   DW_AT_high_pc     : 0x0
    <139>   DW_AT_call_file   : 1
    <13a>   DW_AT_call_line   : 29
    <13b>   DW_AT_call_column : 18
    <13c>   DW_AT_sibling     : <0x14e>
 <3><140>: Abbrev Number: 18 (DW_TAG_formal_parameter)
    <141>   DW_AT_abstract_origin: <0x197>
    <145>   DW_AT_location    : 0x16 (location list)
    <149>   DW_AT_GNU_locviews: 0x14
[...]
 <2><197>: Abbrev Number: 22 (DW_TAG_formal_parameter)
    <198>   DW_AT_name        : (indirect string, offset: 0x2e): this
    <19c>   DW_AT_type        : <0x98>
    <1a0>   DW_AT_artificial  : 1
[...]
Contents of the .debug_loclists section:
[...]
    00000014 v000000000000002 v000000000000004 location view pair

    00000016 v000000000000002 v000000000000004 views at 00000014 for:
             000000000040113f 000000000040113f (DW_OP_implicit_pointer: <0x109>
0)
    00000020 <End of list>

when stepping through the empty subroutine the "this" pointer
and in particular the value of the symbol "t" would be accessible,
like this:

(gdb) s
intermediate (p=...) at empty-inline.cc:29
29          p.get()->call();                 /* line 29 */
(gdb) s
ptr::get (this=<synthetic pointer>)
    at empty-inline.cc:21
21          MyClass* get() { return t; }     /* line 21 */
(gdb) p t
$1 = (MyClass *) 0x416c20

This loclist is of course only accessible when we accept an empty
range as something which may exist at all, thus with my latest
GDB-patch applied:
[0/4] https://sourceware.org/pipermail/gdb-patches/2021-May/179367.html
[1/4] https://sourceware.org/pipermail/gdb-patches/2021-May/179368.html
[2/4] https://sourceware.org/pipermail/gdb-patches/2021-May/179370.html
[3/4] https://sourceware.org/pipermail/gdb-patches/2021-May/179369.html
Currently gdb ignores these subroutine as a kind of nonsense.

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2021-12-28 20:57 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-04-03 16:13 [Bug debug/94474] New: Incorrect DWARF range information for inlined function andrew.burgess at embecosm dot com
2020-04-06  9:59 ` [Bug debug/94474] " bernd.edlinger at hotmail dot de
2020-04-06 10:54 ` andrew.burgess at embecosm dot com
2020-04-06 11:04 ` bernd.edlinger at hotmail dot de
2020-04-06 11:17 ` bernd.edlinger at hotmail dot de
2020-04-06 12:55 ` andrew.burgess at embecosm dot com
2020-04-06 12:57 ` bernd.edlinger at hotmail dot de
2020-04-06 13:15 ` bernd.edlinger at hotmail dot de
2020-04-06 14:16 ` andrew.burgess at embecosm dot com
2020-04-28  2:17 ` bernd.edlinger at hotmail dot de
2020-04-28  9:56 ` andrew.burgess at embecosm dot com
2020-05-16  8:09 ` bernd.edlinger at hotmail dot de
2020-05-17  8:43 ` andrew.burgess at embecosm dot com
2020-05-17  9:05 ` bernd.edlinger at hotmail dot de
2021-12-28 13:16 ` bernd.edlinger at hotmail dot de
2021-12-28 20:57 ` bernd.edlinger at hotmail dot de

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).