aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Burgess <aburgess@redhat.com>2024-11-15 13:07:09 +0000
committerAndrew Burgess <aburgess@redhat.com>2024-11-15 19:22:13 +0000
commit82eff6743b77908a502b4cf9030acc93caf69e74 (patch)
tree30d2ae64efe5860ea170b636cb84f0efc741d086
parent75e11412937864f1f3d1a40820f5eabda6aee1dc (diff)
downloadbinutils-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.exp17
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