From: Tom de Vries <tdevries@suse.de>
To: Andrew Burgess <aburgess@redhat.com>, gdb-patches@sourceware.org
Cc: Bernd Edlinger <bernd.edlinger@hotmail.de>
Subject: Re: [PATCHv6] gdb: fix handling of DW_AT_entry_pc of inlined subroutines
Date: Fri, 15 Nov 2024 09:50:24 +0100 [thread overview]
Message-ID: <9fe35ea1-d99b-444d-bd1b-e3a1f108dd77@suse.de> (raw)
In-Reply-To: <87wmh5objj.fsf@redhat.com>
[-- Attachment #1: Type: text/plain, Size: 7570 bytes --]
On 11/14/24 20:33, Andrew Burgess wrote:
> Tom de Vries <tdevries@suse.de> writes:
>
>> On 11/13/24 17:59, Andrew Burgess wrote:
>>> Andrew Burgess <aburgess@redhat.com> writes:
>>>
>>>> Andrew Burgess <aburgess@redhat.com> writes:
>>>>
>>>>> The entry PC for a DIE, e.g. an inline function, might not be the base
>>>>> address of the DIE. Currently though, in block::entry_pc(), GDB
>>>>> always returns the base address (low-pc or the first address of the
>>>>> first range) as the entry PC.
>>>>>
>>>>> This commit extends the block class to carry the entry PC as a
>>>>> separate member variable. Then the DWARF reader is extended to read
>>>>> and set the entry PC for the block. Now in block::entry_pc(), if the
>>>>> entry PC has been set, this is the value returned.
>>>>>
>>>>> If the entry-pc has not been set to a specific value then the old
>>>>> behaviour of block::entry_pc() remains, GDB will use the block's base
>>>>> address. Not every DIE will set the entry-pc, but GDB still needs to
>>>>> have an entry-pc for every block, so the existing logic supplies the
>>>>> entry-pc for any block where the entry-pc was not set.
>>>>>
>>>>> The DWARF-5 spec for reading the entry PC is a super-set of the spec
>>>>> as found in DWARF-4. For example, if there is no DW_AT_entry_pc then
>>>>> DWARF-4 says to use DW_AT_low_pc while DWARF-5 says to use the base
>>>>> address, which is DW_AT_low_pc or the first address in the first range
>>>>> specified by DW_AT_ranges if there is no DW_AT_low_pc.
>>>>>
>>>>> I have taken the approach of just implementing the DWARF-5 spec for
>>>>> everyone. There doesn't seem to be any benefit to deliberately
>>>>> ignoring a ranges based entry PC value for DWARF-4. If some naughty
>>>>> compiler has emitted that, then lets use it.
>>>>>
>>>>> Similarly, DWARF-4 says that DW_AT_entry_pc is an address. DWARF-5
>>>>> allows an address or a constant, where the constant is an offset from
>>>>> the base address. I allow both approaches for all DWARF versions.
>>>>> There doesn't seem to be any downsides to this approach.
>>>>>
>>>>> I ran into an issue when testing this patch where GCC would have the
>>>>> DW_AT_entry_pc point to an empty range. When GDB parses the ranges
>>>>> any empty ranges are ignored. As a consequence, the entry-pc appears
>>>>> to be outside the address range of a block.
>>>>>
>>>>> The empty range problem is certainly something that we can, and should
>>>>> address, but that is not the focus of this patch, so for now I'm
>>>>> ignoring that problem. What I have done is added a check: if the
>>>>> DW_AT_entry_pc is outside the range of a block then the entry-pc is
>>>>> ignored, GDB will then fall-back to its default algorithm for
>>>>> computing the entry-pc.
>>>>>
>>>>> If/when in the future we address the empty range problem, these
>>>>> DW_AT_entry_pc attributes will suddenly become valid and GDB will
>>>>> start using them. Until then, GDB continues to operate as it always
>>>>> has.
>>>>>
>>>>> An early version of this patch stored the entry-pc within the block
>>>>> like this:
>>>>>
>>>>> std::optional<CORE_ADDR> m_entry_pc;
>>>>>
>>>>> However, a concern was raised that this, on a 64-bit host, effectively
>>>>> increases the size of block by 16-bytes (8-bytes for the CORE_ADDR,
>>>>> and 8-bytes for the std::optional's bool plus padding).
>>>>>
>>>>> If we remove the std::optional part and just use a CORE_ADDR then we
>>>>> need to have a "special" address to indicate if m_entry_pc is in use
>>>>> or not. I don't really like using special addresses; different
>>>>> targets can access different address ranges, even zero is a valid
>>>>> address on some targets.
>>>>>
>>>>> However, Bernd Edlinger suggested storing the entry-pc as an offset,
>>>>> and I think that will resolve my concerns. So, we store the entry-pc
>>>>> as a signed offset from the block's base address (the first address of
>>>>> the first range, or the start() address value if there are now
>>>>> ranges). Remember, ranges can be out of order, in which case the
>>>>> first address of the first range might be greater than the entry-pc.
>>>>>
>>>>> When GDB needs to read the entry-pc we can add the offset onto the
>>>>> blocks base address to recalculate it.
>>>>>
>>>>> With this done, on a 64-bit host, block only needs to increase by
>>>>> 8-bytes.
>>>>>
>>>>> The inline-entry.exp test was originally contributed by Bernd here:
>>>>>
>>>>> https://inbox.sourceware.org/gdb-patches/AS1PR01MB94659E4D9B3F4A6006CC605FE4922@AS1PR01MB9465.eurprd01.prod.exchangelabs.com
>>>>>
>>>>> though I have made some edits, making more use of lib/gdb.exp
>>>>> functions, making the gdb_test output patterns a little tighter, and
>>>>> updating the test to run with Clang. I also moved the test to
>>>>> gdb.opt/ as that seemed like a better home for it.
>>>>>
>>>>> Co-Authored-By: Bernd Edlinger <bernd.edlinger@hotmail.de>
>>>>
>>>> I've pushed the patch attached below. The only changes are some minor
>>>> test tweaks in order to get more of the 'check-all-boards' passing.
>>>> There are still some failures on e.g. gold and fission based boards, but
>>>> I think these might be due to issues with the board file. I'll post a
>>>> patch for those soon.
>>>
>>> I'm aware that this patch has caused a regression on the buildbot[1]. I'm
>>> investigating this but it will be at least tomorrow before I have fix.
>>>
>>
>> In case this helps, I see the same assert in a large amount of ada
>> test-cases.
>>
>> I reproduced the first one using gdb.ada/access_to_packed_array.exp,
>> with system gcc 7 and then with gcc 8. With gcc 9 - 14, the assert no
>> longer reproduces.
>
> Thanks Tom,
>
> I've posted a proposed fix here:
>
> https://inbox.sourceware.org/gdb-patches/23102df35a659d9ef4725d2d3822f08f2790e52d.1731612468.git.aburgess@redhat.com
>
> I would be really grateful if you could give this a try and let me know
> if this fixes all the problems you are seeing.
>
Hi Andrew,
it does fix all the regressions in ada test-cases.
There's one problem left: a test-case introduced by the commit
(gdb.opt/inline-entry.exp) fails with gcc 7 (not with gcc 8 and higher):
...
FAIL: gdb.opt/inline-entry.exp: continue to foo
FAIL: gdb.opt/inline-entry.exp: continue until exit
...
Gdb.log attached.
The test-case sets a breakpoint at foo and bar, and expects that the
program:
- stops at bar,
- stops at foo, and
- exits.
This is what I see when using -O0.
What happens instead (with -O2) is that the program:
- stops at bar,
- stops at bar again,
- stops at foo, and
- exits.
For context, relevant code:
...
inline __attribute__((always_inline)) int
bar (int val)
{
if (global == val)
return 1;
foo (1);
return 1;
}
int
main (void)
{
if ((global && bar (1)) || bar (2))
return 0;
return 1;
}
...
From what I can tell, what happened in source terms is that the
compiler inlined the call "bar (1)", and then moved the first
instruction of bar to before the &&:
In disassembly:
...
00000000004003c0 <main>:
4003c0: mov 0x1c5e(%rip),%eax # Load global to reg
4003c6: test %eax,%eax # If global is zero, set ZF
4003c8: mov 0x1c56(%rip),%eax # Local global to reg (1st of bar)
4003ce: je 4003d8 <main+0x18> # If the ZF is set, skip "bar (1)"
...
At first glance, gdb is behaving ok.
Thanks,
- Tom
> I posted the fix as a new thread because it's not "fix a tiny bug" type
> thing that I'm happy to just commit without giving others a chance to
> fully review it.
>
> Thanks,
> Andrew
>
[-- Attachment #2: gdb.log --]
[-- Type: text/x-log, Size: 6251 bytes --]
Test run by vries on Fri Nov 15 09:04:46 2024
Native configuration is x86_64-pc-linux-gnu
=== gdb tests ===
Schedule of variations:
unix
Running target unix
Using /usr/share/dejagnu/baseboards/unix.exp as board description file for target.
Using /usr/share/dejagnu/config/unix.exp as generic interface file for target.
Using /data/vries/gdb/src/gdb/testsuite/config/unix.exp as tool-and-target-specific interface file.
Running /data/vries/gdb/src/gdb/testsuite/gdb.opt/inline-entry.exp ...
Executing on build: rm -rf /data/vries/gdb/leap-15-5/build/gdb/testsuite/outputs/gdb.opt/inline-entry (timeout = 300)
builtin_spawn -ignore SIGHUP rm -rf /data/vries/gdb/leap-15-5/build/gdb/testsuite/outputs/gdb.opt/inline-entry
gdb_do_cache: universal_compile_options_c ( )
Executing on host: gcc -fdiagnostics-color=never -c -o /data/vries/gdb/leap-15-5/build/gdb/testsuite/temp/2484/ccopts.o /data/vries/gdb/leap-15-5/build/gdb/testsuite/temp/2484/ccopts.c (timeout = 300)
builtin_spawn -ignore SIGHUP gcc -fdiagnostics-color=never -c -o /data/vries/gdb/leap-15-5/build/gdb/testsuite/temp/2484/ccopts.o /data/vries/gdb/leap-15-5/build/gdb/testsuite/temp/2484/ccopts.c
get_compiler_info: gcc-7-5-0
Executing on host: gcc -fno-stack-protector -fdiagnostics-color=never -I/data/vries/gdb/src/gdb/testsuite/lib -c -g -O2 -o /data/vries/gdb/leap-15-5/build/gdb/testsuite/outputs/gdb.opt/inline-entry/inline-entry0.o /data/vries/gdb/src/gdb/testsuite/gdb.opt/inline-entry.c (timeout = 300)
builtin_spawn -ignore SIGHUP gcc -fno-stack-protector -fdiagnostics-color=never -I/data/vries/gdb/src/gdb/testsuite/lib -c -g -O2 -o /data/vries/gdb/leap-15-5/build/gdb/testsuite/outputs/gdb.opt/inline-entry/inline-entry0.o /data/vries/gdb/src/gdb/testsuite/gdb.opt/inline-entry.c
gdb_do_cache: universal_compile_options_c ( )
Executing on host: gcc -fno-stack-protector /data/vries/gdb/leap-15-5/build/gdb/testsuite/outputs/gdb.opt/inline-entry/inline-entry0.o -fdiagnostics-color=never -I/data/vries/gdb/src/gdb/testsuite/lib -g -O2 -lm -o /data/vries/gdb/leap-15-5/build/gdb/testsuite/outputs/gdb.opt/inline-entry/inline-entry (timeout = 300)
builtin_spawn -ignore SIGHUP gcc -fno-stack-protector /data/vries/gdb/leap-15-5/build/gdb/testsuite/outputs/gdb.opt/inline-entry/inline-entry0.o -fdiagnostics-color=never -I/data/vries/gdb/src/gdb/testsuite/lib -g -O2 -lm -o /data/vries/gdb/leap-15-5/build/gdb/testsuite/outputs/gdb.opt/inline-entry/inline-entry
builtin_spawn /data/vries/gdb/leap-15-5/build/gdb/testsuite/../../gdb/gdb -nw -nx -q -iex set height 0 -iex set width 0 -data-directory /data/vries/gdb/leap-15-5/build/gdb/data-directory
(gdb) set height 0
(gdb) set width 0
(gdb) dir
Reinitialize source path to empty? (y or n) y
Source directories searched: $cdir:$cwd
(gdb) dir /data/vries/gdb/src/gdb/testsuite/gdb.opt
Source directories searched: /data/vries/gdb/src/gdb/testsuite/gdb.opt:$cdir:$cwd
(gdb) kill
The program is not being run.
(gdb) file /data/vries/gdb/leap-15-5/build/gdb/testsuite/outputs/gdb.opt/inline-entry/inline-entry
Reading symbols from /data/vries/gdb/leap-15-5/build/gdb/testsuite/outputs/gdb.opt/inline-entry/inline-entry...
(gdb) delete breakpoints
(gdb) info breakpoints
No breakpoints, watchpoints, tracepoints, or catchpoints.
(gdb) break -qualified main
Breakpoint 1 at 0x4003d0: file /data/vries/gdb/src/gdb/testsuite/gdb.opt/inline-entry.c, line 38.
(gdb) run
Starting program: /data/vries/gdb/leap-15-5/build/gdb/testsuite/outputs/gdb.opt/inline-entry/inline-entry
Breakpoint 1, main () at /data/vries/gdb/src/gdb/testsuite/gdb.opt/inline-entry.c:38
38 if ((global && bar (1)) || bar (2))
(gdb) info source
Current source file is /data/vries/gdb/src/gdb/testsuite/gdb.opt/inline-entry.c
Compilation directory is /data/vries/gdb/leap-15-5/build/gdb/testsuite
Located in /data/vries/gdb/binutils-gdb.git/gdb/testsuite/gdb.opt/inline-entry.c
Contains 41 lines.
Source language is c.
Producer is GNU C11 7.5.0 -mtune=generic -march=x86-64 -g -O2 -fno-stack-protector.
Compiled with DWARF 4 debugging format.
Does not include preprocessor macro info.
(gdb) break bar
Breakpoint 2 at 0x4003d8: bar. (2 locations)
(gdb) print /d $bpnum
$1 = 2
(gdb) PASS: gdb.opt/inline-entry.exp: get number of bar breakpoint
break foo
Breakpoint 3 at 0x4004e0: file /data/vries/gdb/src/gdb/testsuite/gdb.opt/inline-entry.c, line 23.
(gdb) print /d $bpnum
$2 = 3
(gdb) PASS: gdb.opt/inline-entry.exp: get number of foo breakpoint
continue
Continuing.
Breakpoint 2.1, bar (val=<optimized out>) at /data/vries/gdb/src/gdb/testsuite/gdb.opt/inline-entry.c:29
29 if (global == val)
(gdb) PASS: gdb.opt/inline-entry.exp: continue to bar
continue
Continuing.
Breakpoint 2.2, bar (val=2) at /data/vries/gdb/src/gdb/testsuite/gdb.opt/inline-entry.c:29
29 if (global == val)
(gdb) FAIL: gdb.opt/inline-entry.exp: continue to foo
continue
Continuing.
Breakpoint 3, foo (arg=arg@entry=1) at /data/vries/gdb/src/gdb/testsuite/gdb.opt/inline-entry.c:23
23 global += arg;
(gdb) FAIL: gdb.opt/inline-entry.exp: continue until exit
testcase /data/vries/gdb/src/gdb/testsuite/gdb.opt/inline-entry.exp completed in 0 seconds
=== gdb Summary ===
# of expected passes 3
# of unexpected failures 2
Executing on host: /data/vries/gdb/leap-15-5/build/gdb/testsuite/../../gdb/gdb -nw -nx -q -iex "set height 0" -iex "set width 0" -data-directory /data/vries/gdb/leap-15-5/build/gdb/data-directory --version (timeout = 300)
builtin_spawn -ignore SIGHUP /data/vries/gdb/leap-15-5/build/gdb/testsuite/../../gdb/gdb -nw -nx -q -iex set height 0 -iex set width 0 -data-directory /data/vries/gdb/leap-15-5/build/gdb/data-directory --version
GNU gdb (GDB) 16.0.50.20241114-git
Copyright (C) 2024 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
/data/vries/gdb/leap-15-5/build/gdb/gdb version 16.0.50.20241114-git -nw -nx -q -iex "set height 0" -iex "set width 0" -data-directory /data/vries/gdb/leap-15-5/build/gdb/data-directory
runtest completed at Fri Nov 15 09:04:46 2024
next prev parent reply other threads:[~2024-11-15 8:49 UTC|newest]
Thread overview: 41+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-10-16 15:47 [PATCH] " Andrew Burgess
2024-10-17 20:03 ` Tom Tromey
2024-10-18 10:06 ` Andrew Burgess
2024-10-18 13:57 ` Andrew Burgess
2024-10-18 10:26 ` Gerlicher, Klaus
2024-10-18 13:55 ` Andrew Burgess
2024-10-18 13:53 ` [PATCHv2] " Andrew Burgess
2024-10-28 13:45 ` [PATCHv3] " Andrew Burgess
2024-10-29 14:49 ` [PATCHv4] " Andrew Burgess
2024-10-29 15:28 ` Bernd Edlinger
2024-10-31 10:57 ` Andrew Burgess
2024-10-31 14:01 ` Bernd Edlinger
2024-10-31 14:56 ` Andrew Burgess
2024-10-29 16:34 ` Bernd Edlinger
2024-10-31 10:59 ` Andrew Burgess
2024-10-31 15:00 ` [PATCHv5] " Andrew Burgess
2024-11-01 18:13 ` Tom Tromey
2024-11-01 20:27 ` Bernd Edlinger
2024-11-05 11:25 ` Andrew Burgess
2024-11-05 15:26 ` Bernd Edlinger
2024-11-05 16:52 ` Andrew Burgess
2024-11-05 19:57 ` Bernd Edlinger
2024-11-05 11:21 ` [PATCHv6] " Andrew Burgess
2024-11-13 13:49 ` Andrew Burgess
2024-11-13 16:59 ` Andrew Burgess
2024-11-14 9:20 ` Tom de Vries
2024-11-14 19:33 ` Andrew Burgess
2024-11-15 8:50 ` Tom de Vries [this message]
2024-11-15 10:53 ` Bernd Edlinger
2024-11-15 14:00 ` Andrew Burgess
2024-11-15 14:30 ` Tom de Vries
2024-11-15 16:46 ` Andrew Burgess
2024-11-15 19:24 ` Andrew Burgess
2024-11-17 23:52 ` Bernd Edlinger
2024-11-19 9:29 ` Andrew Burgess
2024-11-15 17:00 ` Bernd Edlinger
2024-11-15 13:45 ` Andrew Burgess
2024-10-29 15:29 ` [PATCHv3] " Sam James
2024-10-31 9:48 ` Andrew Burgess
2024-10-18 14:24 ` [PATCH] " Bernd Edlinger
2024-10-28 13:26 ` Andrew Burgess
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=9fe35ea1-d99b-444d-bd1b-e3a1f108dd77@suse.de \
--to=tdevries@suse.de \
--cc=aburgess@redhat.com \
--cc=bernd.edlinger@hotmail.de \
--cc=gdb-patches@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).