From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 48) id 7A0283851C24; Tue, 28 Apr 2020 09:56:41 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 7A0283851C24 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1588067801; bh=X1sYQ0g/F2nSX9bQclH3zNIUB4fPm8nOn14vJ0Qv6cw=; h=From:To:Subject:Date:In-Reply-To:References:From; b=esBenlq5ZcHwggDwDHcBpBbwCIONl9+fGIg95KG8vlqFI+38cjxMJODcrC3AYY1Nk yVbMkqYMfm3U0ZsRMcSt+NvNZWPiP/24suVr33M4tnL8DH4UXdYhcs7PWwPT/UgTsw Zuk5mSFRuIblxWXovQkQu5tSbxeHEv/CYM59RPP8= From: "andrew.burgess at embecosm dot com" To: gcc-bugs@gcc.gnu.org Subject: [Bug debug/94474] Incorrect DWARF range information for inlined function Date: Tue, 28 Apr 2020 09:56:41 +0000 X-Bugzilla-Reason: CC X-Bugzilla-Type: changed X-Bugzilla-Watch-Reason: None X-Bugzilla-Product: gcc X-Bugzilla-Component: debug X-Bugzilla-Version: 9.2.0 X-Bugzilla-Keywords: wrong-debug X-Bugzilla-Severity: normal X-Bugzilla-Who: andrew.burgess at embecosm dot com X-Bugzilla-Status: UNCONFIRMED X-Bugzilla-Resolution: X-Bugzilla-Priority: P3 X-Bugzilla-Assigned-To: unassigned at gcc dot gnu.org X-Bugzilla-Target-Milestone: --- X-Bugzilla-Flags: X-Bugzilla-Changed-Fields: Message-ID: In-Reply-To: References: Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Bugzilla-URL: http://gcc.gnu.org/bugzilla/ Auto-Submitted: auto-generated MIME-Version: 1.0 X-BeenThere: gcc-bugs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-bugs mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 28 Apr 2020 09:56:41 -0000 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=3D94474 --- Comment #10 from Andrew Burgess --- 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 =3D<8e8> Unknown AT value: 2138: 3=3D, 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 =3D00000030=3D: #+BEGIN_EXAMPLE Contents of the .debug_ranges section: Offset Begin End 00000000 0000000000401160 00000000004011ca 00000000 0000000000401040 0000000000401045 00000000 00000030 0000000000401165 0000000000401165 (start =3D=3D end) 00000030 0000000000401169 0000000000401173 00000030 0000000000401040 0000000000401045 00000030 00000030 0000000000401165 0000000000401165 (start =3D=3D end) 00000030 0000000000401169 0000000000401173 00000030 0000000000401040 0000000000401045 00000030 00000070 0000000000401160 00000000004011ca 00000070 0000000000401040 0000000000401045 00000070 0000000000401050 0000000000401065 00000070 #+END_EXAMPLE Next, here's a snippet of disassembler, this covers two of the ranges from the above, the empty one =3D0x401165=3D to =3D0x401165=3D, and then = =3D0x401169=3D to =3D0x401173=3D. The range =3D0x401040=3D to =3D0x401045=3D 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 V= iew=20 Stmt step-and-next-inline.cc 50 0x401160=20= =20=20=20=20=20=20=20=20 x step-and-next-inline.cc 51 0x401160 = 1=20 x step-and-next-inline.cc 54 0x401160 = 2 ./step-and-next-inline.h:[++] step-and-next-inline.h 32 0x401165=20= =20=20=20=20=20=20=20=20 x step-and-next-inline.h 34 0x401165 = 1=20 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=20= =20=20=20=20=20=20=20=20 x step-and-next-inline.h 37 0x401173 = 1=20 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_EXAMPLE The changes are: (1) The empty range at =3D0x401165=3D is now folded into the following range, which coincidentally started at the very next instruction anyway. (2) The range previously ending at =3D0x401173=3D now ends at =3D0x401176= =3D, 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 =3D0x401173=3D 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!=