diff options
author | Andrew Burgess <aburgess@redhat.com> | 2024-11-15 13:07:09 +0000 |
---|---|---|
committer | Andrew Burgess <aburgess@redhat.com> | 2024-11-15 19:22:13 +0000 |
commit | 82eff6743b77908a502b4cf9030acc93caf69e74 (patch) | |
tree | 30d2ae64efe5860ea170b636cb84f0efc741d086 | |
parent | 75e11412937864f1f3d1a40820f5eabda6aee1dc (diff) | |
download | binutils-82eff6743b77908a502b4cf9030acc93caf69e74.zip binutils-82eff6743b77908a502b4cf9030acc93caf69e74.tar.gz binutils-82eff6743b77908a502b4cf9030acc93caf69e74.tar.bz2 |
gdb/testsuite: skip gdb.opt/inline-entry.exp for gcc 7 and older
It was pointed out that the recently added gdb.opt/inline-entry.exp
test would fail when run using gcc 7 and earlier, on an x86-64 target:
https://inbox.sourceware.org/gdb-patches/9fe35ea1-d99b-444d-bd1b-e3a1f108dd77@suse.de
Bernd Edlinger points out that, for gcc, the test relies on the
-gstatement-frontiers work which was added in gcc 8.x:
https://inbox.sourceware.org/gdb-patches/DU2PR08MB10263357597688D9D66EA745CE4242@DU2PR08MB10263.eurprd08.prod.outlook.com
For gcc 7.x and older, without the -gstatement-frontiers work, the
compiler uses DW_AT_entry_pc differently, which leads to a poorer
debug experience.
Here is the interesting source line from inline-entry.c:
if ((global && bar (1)) || bar (2))
And here's some of the relevant disassembly output:
Dump of assembler code for function main:
0x401020 <+0>: mov 0x3006(%rip),%eax (1)
0x401026 <+6>: test %eax,%eax (2)
0x401028 <+8>: mov 0x2ffe(%rip),%eax (3)
0x40102e <+14>: je 0x401038 <main+24> (4)
0x401030 <+16>: sub $0x1,%eax (5)
0x401033 <+19>: jne 0x40103d <main+29> (6)
Lines (1), (2), and (4) represent the check of 'global'. However,
line (3) is actually the first instruction for 'bar' which has been
inlined. Lines (5) and (6) are also part of the first inlined 'bar'
function.
If the check of 'global' returns false then the first call to 'bar'
should never happen, this is accomplished by the branch at (4) being
taken.
For gcc 8+, gcc generates a DW_AT_entry_pc with the value 0x401030,
this is where GDB places a breakpoint for 'bar', and this address is
after the branch at line (4), and so, if the call to 'bar' never
happens, the breakpoint is never hit.
For gcc 7 and older, gcc generates a DW_AT_entry_pc with the value
0x401028, which is the first address associated with the inline 'bar'
function. Unfortunately, this address is also before the check of
'global' has completed, this means that GDB hits the 'bar' breakpoint
before the inferior has decided if 'bar' should actually be called or
not.
I don't think there's really much GDB can do in the older gcc
versions, we are placing the breakpoint at the entry point, and this
is within bar. Given that this test does really depend on the newer
gcc behaviour, I think the only sensible solution is to skip this test
when an older version of gcc is being used.
I've incorporated the check for -gstatement-frontiers support that
Bernd suggested and now the test will be skipped for older versions of
GCC.
Approved-By: Tom de Vries <tdevries@suse.de>
-rw-r--r-- | gdb/testsuite/gdb.opt/inline-entry.exp | 17 |
1 files changed, 17 insertions, 0 deletions
diff --git a/gdb/testsuite/gdb.opt/inline-entry.exp b/gdb/testsuite/gdb.opt/inline-entry.exp index 6f87ea3..16443c6 100644 --- a/gdb/testsuite/gdb.opt/inline-entry.exp +++ b/gdb/testsuite/gdb.opt/inline-entry.exp @@ -21,10 +21,27 @@ # Testing with Clang 9.0.1 and 15.0.2 seemed to indicate that the # Clang generated code didn't depend on the entry_pc being parsed. +# Older versions of GCC, those prior to the -gstatement-frontiers work +# added in 8.x, would generate DW_AT_entry_pc values pointing to the +# first instruction of an inlined function. This first instruction +# could then be reordered such that the first instruction might be +# executed even when the actual call to the inline function ended up +# being skipped. GDB can then hit a breakpoint for a function that +# ends up never being called. +# +# This test is specifically testing that GDB correctly handles the +# case where DW_AT_entry_pc is not the first instruction of an inlined +# function, as can be the case in gcc 8.x with the +# -gstatement-frontiers work in place. +require {expr ![is_c_compiler_gcc] || [supports_statement_frontiers]} + standard_testfile set options {debug optimize=-O2} lappend_include_file options $srcdir/lib/attributes.h +if { [supports_statement_frontiers] } { + lappend options additional_flags=-gstatement-frontiers +} if { [prepare_for_testing "failed to prepare" $binfile $srcfile $options] } { return |