aboutsummaryrefslogtreecommitdiff
path: root/gdb/testsuite/gdb.server/build-id-seqno.exp
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/testsuite/gdb.server/build-id-seqno.exp')
-rw-r--r--gdb/testsuite/gdb.server/build-id-seqno.exp200
1 files changed, 200 insertions, 0 deletions
diff --git a/gdb/testsuite/gdb.server/build-id-seqno.exp b/gdb/testsuite/gdb.server/build-id-seqno.exp
new file mode 100644
index 0000000..7db1f11
--- /dev/null
+++ b/gdb/testsuite/gdb.server/build-id-seqno.exp
@@ -0,0 +1,200 @@
+# This testcase is part of GDB, the GNU debugger.
+#
+# Copyright 2024 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Setup a .build-id/ based debug directory containing multiple entries
+# for the same build-id, with each entry given a different sequence
+# number.
+#
+# Ensure that GDB will scan over broken symlinks for the same build-id
+# (but different sequence number) to find later working symlinks.
+#
+# This test places the build-id files within a directory next to where
+# gdbserver is started, and places a relative address in the
+# debug-file-directory, in this way we require GDB to find the debug
+# information via gdbserver.
+
+require {!is_remote host}
+
+load_lib gdbserver-support.exp
+
+require allow_gdbserver_tests
+
+standard_testfile
+
+if {[build_executable "failed to prepare" $testfile $srcfile] == -1} {
+ return -1
+}
+
+# Split out BINFILE.debug. Remove debug from BINFILE.
+if {[gdb_gnu_strip_debug $binfile] != 0} {
+ return -1
+}
+
+# Get the '.build-id/xx/xxx...xxx' part of the filename.
+set build_id_filename [build_id_debug_filename_get $binfile]
+
+# Hide (rename) BINFILE.debug, this should ensure GDB can't find it
+# directly but needs to look for the build-id based file in the debug
+# directory.
+set hidden_debuginfo [standard_output_file "hidden_$testfile.debug"]
+remote_exec build "mv ${binfile}.debug $hidden_debuginfo"
+
+# A filename that doesn't exist. Some symlinks will point at this
+# file.
+set missing_debuginfo "missing_debuginfo"
+
+# Helper called from gdb_finish when the 'target' is remote. Ensure the
+# debug directory we create is deleted.
+proc cleanup_remote_target {} {
+ remote_exec target "rm -fr debug/"
+}
+
+if { ![is_remote target] } {
+ set gdbserver_dir [standard_output_file "gdbserver-dir"]/
+} else {
+ lappend gdb_finish_hooks cleanup_remote_target
+ set gdbserver_dir ""
+}
+
+# Copy files to the target (if needed).
+set target_binfile [gdb_remote_download target $binfile]
+set target_debuginfo [gdb_remote_download target $hidden_debuginfo]
+
+# Setup the debug information on the target.
+set debugdir "${gdbserver_dir}debug"
+remote_exec target \
+ "mkdir -p $debugdir/[file dirname $build_id_filename]"
+remote_exec target \
+ "ln -sf $target_debuginfo $debugdir/$build_id_filename"
+
+# Start GDB and load global BINFILE. If DEBUGINFO_FILE is not the
+# empty string then this contains the '.build-id/xx/xxx....xxxx' part
+# of the filename which we expect GDB to read from the remote target.
+# If DEBUGINFO_FILE is the empty string then we don't expect GDB to
+# find any debug information.
+proc load_binfile_check_debug_is_found { debuginfo_file testname } {
+ with_test_prefix "$testname" {
+ with_timeout_factor 5 {
+ # Probing for .build-id based debug files on remote
+ # targets uses the vFile:stat packet by default, though
+ # there is a work around that avoids this which can be
+ # used if GDB is connected to an older gdbserver without
+ # 'stat' support.
+ #
+ # Check the work around works by disabling use of the
+ # vFile:stat packet.
+ foreach_with_prefix stat_pkt {auto off} {
+ clean_restart
+
+ gdb_test_no_output "set debug-file-directory debug" \
+ "set debug-file-directory"
+
+ gdb_test_no_output "set sysroot target:"
+
+ gdb_test "set remote hostio-stat-packet $stat_pkt"
+
+ # Make sure we're disconnected, in case we're testing with an
+ # extended-remote board, therefore already connected.
+ gdb_test "disconnect" ".*"
+
+ # Start gdbserver. This needs to be done after starting GDB. When
+ # gdbserver is running local to GDB, start gdbserver in a sub-directory,
+ # this prevents GDB from finding the debug information itself.
+ if { ![is_remote target] } {
+ with_cwd $::gdbserver_dir {
+ set res [gdbserver_start "" $::target_binfile]
+ }
+ } else {
+ set res [gdbserver_start "" $::target_binfile]
+ }
+ set gdbserver_protocol [lindex $res 0]
+ set gdbserver_gdbport [lindex $res 1]
+
+ # Connect to gdbserver. The output will be placed into the global
+ # GDB_TARGET_REMOTE_CMD_MSG, and we'll match against this below.
+ gdb_assert {[gdb_target_cmd $gdbserver_protocol $gdbserver_gdbport] == 0} \
+ "connect to gdbserver"
+
+ if { $debuginfo_file ne "" } {
+ gdb_assert { [regexp "Reading symbols from target:debug/[string_to_regexp $debuginfo_file]\\.\\.\\." \
+ $::gdb_target_remote_cmd_msg] } \
+ "debuginfo was read via build-id"
+ gdb_assert { [regexp "Reading debug/[string_to_regexp $debuginfo_file] from remote target\\.\\.\\." \
+ $::gdb_target_remote_cmd_msg] } \
+ "debuginfo was read from remote target"
+ } else {
+ gdb_assert { [regexp "\\(No debugging symbols found in \[^\r\n\]+/$::testfile\\)" \
+ $::gdb_target_remote_cmd_msg] }
+ }
+ }
+ }
+ }
+}
+
+# Return a copy of FILENAME, which should end '.debug', with NUMBER
+# added, e.g. add_seqno 1 "foo.debug" --> "foo.1.debug".
+proc add_seqno { number filename } {
+ return [regsub "\.debug\$" $filename ".${number}.debug"]
+}
+
+# Precompute sequence numbered build-id filenames.
+set build_id_1_filename [add_seqno 1 $build_id_filename]
+set build_id_2_filename [add_seqno 2 $build_id_filename]
+set build_id_3_filename [add_seqno 3 $build_id_filename]
+
+load_binfile_check_debug_is_found $build_id_filename \
+ "find debuginfo with a single build-id file"
+
+remote_exec target "ln -fs $target_debuginfo \
+ $debugdir/$build_id_1_filename"
+remote_exec target "ln -fs $target_debuginfo \
+ $debugdir/$build_id_2_filename"
+remote_exec target "ln -fs $target_debuginfo \
+ $debugdir/$build_id_3_filename"
+
+load_binfile_check_debug_is_found $build_id_filename \
+ "find debuginfo with 4 build-id files"
+
+remote_exec target "ln -fs $missing_debuginfo $debugdir/$build_id_filename"
+
+load_binfile_check_debug_is_found $build_id_1_filename \
+ "find debuginfo, first build-id file is bad"
+
+remote_exec target "ln -fs $missing_debuginfo \
+ $debugdir/$build_id_1_filename"
+remote_exec target "ln -fs $missing_debuginfo \
+ $debugdir/$build_id_3_filename"
+
+load_binfile_check_debug_is_found $build_id_2_filename \
+ "find debuginfo, first 2 build-id files are bad"
+
+remote_exec target "ln -fs $missing_debuginfo \
+ $debugdir/$build_id_2_filename"
+
+load_binfile_check_debug_is_found "" \
+ "cannot find debuginfo, all build-id files are bad"
+
+remote_exec target "ln -fs $target_debuginfo \
+ $debugdir/$build_id_3_filename"
+
+load_binfile_check_debug_is_found $build_id_3_filename \
+ "find debuginfo, last build-id file is good"
+
+remote_exec target "rm -f $debugdir/$build_id_1_filename"
+
+load_binfile_check_debug_is_found "" \
+ "cannot find debuginfo, file with seqno 1 is missing"