aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Burgess <aburgess@redhat.com>2024-12-15 16:06:02 +0000
committerAndrew Burgess <aburgess@redhat.com>2024-12-16 16:22:10 +0000
commitf1b4718cbdfc3332b737fbea8612448586f5184b (patch)
treeb36938bc271d503c8834b19fb5da00595c1a3eab
parentea17e06b50ecc045c311c348d28404f711ac3737 (diff)
downloadgdb-f1b4718cbdfc3332b737fbea8612448586f5184b.zip
gdb-f1b4718cbdfc3332b737fbea8612448586f5184b.tar.gz
gdb-f1b4718cbdfc3332b737fbea8612448586f5184b.tar.bz2
gdb/testsuite: rename test source file to avoid glibc clash
After posting this series: https://inbox.sourceware.org/gdb-patches/cover.1733742925.git.aburgess@redhat.com I got a failure report from the Linaro CI system. I eventually tracked the issue down to a filename clash with glibc. I was able to reproduce the issue when I installed the glibc debug information on to my local machine, and ran the gdb.base/dlmopen.exp test as updated in the above series. Here's what's happening: There is a file called dlmopen.c within glibc, within the glibc source tree the file can be found at ./dlfcn/dlmopen.c. When this file is compiled it appears that the glibc build system first enters the dlfcn directory, and then compiles the file using the relative path ./dlmopen.c, here's a snippet of the DWARF: <0><d5d27>: Abbrev Number: 12 (DW_TAG_compile_unit) <d5d28> DW_AT_producer : (alt indirect string, offset: 0x16433) t <d5d2c> DW_AT_language : 29 (C11) <d5d2d> DW_AT_name : (indirect line string, offset: 0x5c8f): dlmopen.c <d5d31> DW_AT_comp_dir : (indirect line string, offset: 0xb478): /usr/src/debug/glibc-2.38-19.fc39.x86_64/dlfcn <d5d35> DW_AT_low_pc : 0x8a4c0 <d5d3d> DW_AT_high_pc : 408 <d5d3f> DW_AT_stmt_list : 0x68ec1 The important thing here is the DW_AT_name, which is just "dlmopen.c". The gdb.base/dlmopen.exp test also has a source file called "dlmopen.c". The dlmopen.exp test makes use of the clean_restart TCL proc, which calls gdb_reinitialize_dir, which resets the source directories search path to '$cdir:$cwd', and then prepends the test source directory to the front of the list, so the source directory search path will look something like: /tmp/src/gdb/testsuite/gdb.base/gdb.base:$cdir:$cwd In the existing test we try to place a breakpoint on 'dlmopen.c:64'. This is the line tagged 'bp.main' in the source file. This currently works fine. GDB searches through the symtabs and finds two matches, the test dlmopen.c, and the glibc dlmopen.c. For each GDB tries to convert line 64 into an address. For the testsuite source file this is fine, we get the address of the line tagged 'bp.main' from the source, and the breakpoint is created. For the glibc source file though, at least, for the version available to me, line 64 happens to be the closing '}' of a function, and there isn't a line table entry for this exact line. So GDB searches forward looking for the next line in order to place a breakpoint there. The next line GDB finds is the start of the next function, and so GDB rejects this location due to commit: commit dcaa85e58c4ef50a92908e071ded631ce48c971c Date: Wed May 1 10:47:47 2024 +0100 gdb: reject inserting breakpoints between functions So we managed to avoid creating two breakpoint locations in this case, but only by pure good luck. In my updates to the test though I try to create a breakpoint at line 61 in addition to the breakpoint at line 64. So now the breakpoint spec is 'dlmopen.c:61'. Just as before, GDB identifies the 'dlmopen.c' could mean two files, and searches for line 61 in both. The test source works as expected and the breakpoint is created in the desired location. But this time, line 61 in the glibc source file is an actual line, with actual code, and so GDB places a breakpoint at this location. This second breakpoint, in glibc is entirely unexpected (by the dlmopen.exp test script). Unfortunately, the inferior hits this second glibc breakpoint before it hits the actual breakpoint within the main test executable, this throws the test off and causes some failures. In trying to fix this, I did wonder if I could just specify the full path to the source file, instead of using just 'dlmopen.c:61'. However, this doesn't work. Remember that the glibc source file is recorded as just 'dlmopen.c'. So, when GDB tries to figure out the absolute path to this source file, the source directory search path is used. In this case, the first entry in the source directory search path is the gdb.base/ directory in the GDB source tree. GDB looks in this directory and finds a dlmopen.c, and so GDB assumes that this is the file in question. Thus, GDB actually thinks that both files _are_ the same source file. Indeed, when GDB stops at the incorrect (glibc) breakpoint, and lists the source code, it actually lists the source code from the correct file. This confused me to begin with, GDB reported the wrong function (the glibc function), but listed code from the correct file and line. Now on my machine I have installed the package that provides the glibc source code. If I change the source directory search path so that $cdir is first instead of the gdb.base/ from the GDB source tree, this fixes the listing the wrong file problem. GDB does not realise that the files are different, and if I create the breakpoint using the absolute path then only a single breakpoint location is created. However, this relies on the developer having both the glibc debug information, and the glibc source package installed, this doesn't seem like a great requirement to have in place. So instead, I propose that we just take the easy way out, rename the test source file. By doing this all the issues are avoided. The test now creates a breakpoint at 'dlmopen-main.c:61', and there is only one file with this name found, so we only get a single breakpoint location created. I renamed the source file, but not the dlmopen.exp file because the test already makes use of multiple source files, so having a range of different names didn't feel that bad, but if this bothers people, I could rename both the .exp and main .c file, just let me know. If you want to explore this issue for yourself then try with installing the glibc debug information for your system, and ensure that your GDBs under test are able to find the glibc debug information. You can then either apply the series I linked above, or, you can modify the existing test source so that the line tagged as 'bp.main' becomes line 61, I just deleted 3 lines from the big comment at the head of the file. Of course, reproducing this does depend on how glibc is compiled, which could change from system to system, or overtime. I reproduced this issue on Fedora 39 with glibc-2.38-19. With this patch applied I no longer see any regressions when I apply the above linked series. While making these changes I took the opportunity to update the test script to make better use of standard_testfile and build_executable. Reviewed-By: Keith Seitz <keiths@redhat.com> Approved-By: Tom Tromey <tom@tromey.com>
-rw-r--r--gdb/testsuite/gdb.base/dlmopen-main.c (renamed from gdb/testsuite/gdb.base/dlmopen.c)0
-rw-r--r--gdb/testsuite/gdb.base/dlmopen.exp56
2 files changed, 42 insertions, 14 deletions
diff --git a/gdb/testsuite/gdb.base/dlmopen.c b/gdb/testsuite/gdb.base/dlmopen-main.c
index 196d13a..196d13a 100644
--- a/gdb/testsuite/gdb.base/dlmopen.c
+++ b/gdb/testsuite/gdb.base/dlmopen-main.c
diff --git a/gdb/testsuite/gdb.base/dlmopen.exp b/gdb/testsuite/gdb.base/dlmopen.exp
index 264c518..dee046a 100644
--- a/gdb/testsuite/gdb.base/dlmopen.exp
+++ b/gdb/testsuite/gdb.base/dlmopen.exp
@@ -23,30 +23,58 @@
require allow_dlmopen_tests
-standard_testfile
+# Don't use 'dlmopen.c' as the source file name, glibc also has a file
+# with that name. Within our tests, we set the source directory search
+# path order to:
+#
+# (1) the test source directory,
+# (2) the compilation directory, and then
+# (3) the current working directory.
+#
+# Because (1) is first when we try to place a breakpoint on
+# 'dlmopen.c', if the test source file has that name, then GDB will
+# find both the test source file, and the source file from glibc.
+#
+# We could work around this by making (2) first in the source
+# directory list, but that only works when the glibc source is
+# installed. If it isn't then GDB will try the compilation directory,
+# fail to find the source, then try the test source directory, get a
+# hit, and so still confuse the two files.
+#
+# You might think the problem can be solved by specifying the absolute
+# path to the source file. This doesn't work because the glibc file
+# has its filename recorded as just "dlmopen.c", as such GDB has to
+# figure out an absolute path to the file (if possible). The absolute
+# path is figured out based on where GDB can find a matching file in
+# the source directory list, and because of the confusion above, GDB
+# will usually think the test 'dlmopen.c' and the glibc 'dlmopen.c'
+# are actually the same file.
+#
+# The conclusion is that it is just easier to rename the test source
+# file to avoid conflicts with glibc.
+
+standard_testfile -main.c -lib.c -lib-dep.c
set basename_lib dlmopen-lib
-set srcfile_lib $srcdir/$subdir/$basename_lib.c
+set srcfile_lib $srcfile2
set binfile_lib1 [standard_output_file $basename_lib.1.so]
set binfile_lib2 [standard_output_file $basename_lib.2.so]
-set srcfile_lib_dep $srcdir/$subdir/$basename_lib-dep.c
+set srcfile_lib_dep $srcfile3
set binfile_lib_dep [standard_output_file $basename_lib-dep.so]
-if { [gdb_compile_shlib $srcfile_lib_dep $binfile_lib_dep {debug}] != "" } {
- untested "failed to prepare shlib"
- return -1
+if { [build_executable "build shlib dep" $binfile_lib_dep $srcfile_lib_dep \
+ {debug shlib}] == -1 } {
+ return
}
-if { [gdb_compile_shlib $srcfile_lib $binfile_lib1 \
- [list debug shlib_load libs=$binfile_lib_dep]] != "" } {
- untested "failed to prepare shlib"
- return -1
+if { [build_executable "build shlib" $binfile_lib1 $srcfile_lib \
+ [list debug shlib_load shlib libs=$binfile_lib_dep]] == -1 } {
+ return
}
-if { [gdb_compile_shlib $srcfile_lib $binfile_lib2 \
- [list debug shlib_load libs=$binfile_lib_dep]] != "" } {
- untested "failed to prepare shlib"
- return -1
+if { [build_executable "build shlib" $binfile_lib2 $srcfile_lib \
+ [list debug shlib_load shlib libs=$binfile_lib_dep]] == -1 } {
+ return
}
if { [prepare_for_testing "failed to prepare" $testfile $srcfile \