# Copyright 2024-2025 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 .
# Check GDB's ability to auto-load the executable based on the file
# names extracted from the core file.
#
# Currently, only Linux supports reading full executable and arguments
# from a core file.
require {is_any_target "*-*-linux*" "*-*-freebsd*"}
standard_testfile
if {[build_executable $testfile.exp $testfile $srcfile {debug build-id}] == -1} {
untested "failed to compile"
return -1
}
# Load the COREFILE and confirm that GDB auto-loads the executable.
# The symbols should be read from SYMBOL_FILE and the core file should
# be reported as generated by GEN_FROM_FILE.
proc test_load { corefile symbol_file gen_from_file } {
clean_restart
set saw_generated_line false
set saw_reading_symbols false
gdb_test_multiple "core-file $corefile" "load core file" {
-re "^Reading symbols from [string_to_regexp $symbol_file]\\.\\.\\.\r\n" {
set saw_reading_symbols true
exp_continue
}
-re "^Core was generated by `[string_to_regexp $gen_from_file]'\\.\r\n" {
set saw_generated_line true
exp_continue
}
-re "^$::gdb_prompt $" {
gdb_assert { $saw_generated_line && $saw_reading_symbols} \
$gdb_test_name
}
-re "^\[^\r\n\]*\r\n" {
exp_continue
}
}
}
with_test_prefix "absolute path" {
# Generate a core file, this uses an absolute path to the
# executable.
with_test_prefix "to file" {
set corefile [core_find $binfile]
if {$corefile == ""} {
untested "unable to create corefile"
return 0
}
set corefile_1 "$binfile.1.core"
remote_exec build "mv $corefile $corefile_1"
test_load $corefile_1 $binfile $binfile
}
# And create a symlink, and repeat the test using an absolute path
# to the symlink.
with_test_prefix "to symlink" {
set symlink_name "symlink_1"
set symlink [standard_output_file $symlink_name]
with_cwd [standard_output_file ""] {
remote_exec build "ln -s ${testfile} $symlink_name"
}
set corefile [core_find $symlink]
if {$corefile == ""} {
untested "unable to create corefile"
return 0
}
set corefile_2 "$binfile.2.core"
remote_exec build "mv $corefile $corefile_2"
test_load $corefile_2 $symlink $symlink
}
# Like the previous test, except this time, delete the symlink
# after generating the core file. GDB should be smart enough to
# figure out that we can use the underlying TESTFILE binary.
with_test_prefix "to deleted symlink" {
set symlink_name "symlink_2"
set symlink [standard_output_file $symlink_name]
with_cwd [standard_output_file ""] {
remote_exec build "ln -s ${testfile} $symlink_name"
}
set corefile [core_find $symlink]
if {$corefile == ""} {
untested "unable to create corefile"
return 0
}
set corefile_3 "$binfile.3.core"
remote_exec build "mv $corefile $corefile_3"
remote_exec build "rm -f $symlink"
# FreeBSD is unable to figure out the actual underlying mapped
# file, so when the symlink is deleted, FeeeBSD is stuck.
#
# There is some argument that this shouldn't even be a
# failure, the user ran the symlink, and if the symlink is
# gone, should we really expect GDB to find the underlying
# file? That we can on Linux is really just a quirk of how
# the mapped file list works.
setup_xfail "*-*-freebsd*"
test_load $corefile_3 $binfile $symlink
}
# Generate the core file with an absolute path to the executable,
# but move the core file and executable into a single directory
# together so GDB can't use the absolute path to find the
# executable.
#
# GDB should still find the executable though, but looking in the
# same directory as the core file.
with_test_prefix "in side directory" {
set binfile_2 [standard_output_file ${testfile}_2]
remote_exec build "cp $binfile $binfile_2"
set corefile [core_find $binfile_2]
if {$corefile == ""} {
untested "unable to create corefile"
return 0
}
set corefile_4 "$binfile.4.core"
remote_exec build "mv $corefile $corefile_4"
set side_dir [standard_output_file side_dir]
remote_exec build "mkdir -p $side_dir"
remote_exec build "mv $binfile_2 $side_dir"
remote_exec build "mv $corefile_4 $side_dir"
set relocated_corefile_4 [file join $side_dir [file tail $corefile_4]]
set relocated_binfile_2 [file join $side_dir [file tail $binfile_2]]
test_load $relocated_corefile_4 $relocated_binfile_2 $binfile_2
}
}
with_test_prefix "relative path" {
# Generate a core file using relative a path. We ned to work
# around the core_find proc a little here. The core_find proc
# creates a sub-directory using standard_output_file and runs the
# test binary from inside that directory.
#
# Usually core_find is passed an absolute path, so thre's no
# problem, but we want to pass a relative path.
#
# So setup a directory structure like this:
#
# corefile-find-exec/
# reldir/
#
# workdir/
#
# Place a copy of BINFILE in 'reldir/' and switch to workdir, use
# core_find which will create a sibling directory of workdir, and
# run the relative path from there. We then move the generated
# core file back into 'workdir/', this leaves a tree like:
#
# corefile-find-exec/
# reldir/
#
# workdir/
#
#
# Now we can ask GDB to open the core file, if all goes well GDB
# should make use of the relative path encoded in the core file to
# locate the executable in 'reldir/'.
#
# We also setup a symlink in 'reldir' that points to the
# executable and repeat the test, but this time executing the
# symlink.
set reldir_name "reldir"
set reldir [standard_output_file $reldir_name]
remote_exec build "mkdir -p $reldir"
set alt_testfile "alt_${testfile}"
set binfile_3 "$reldir/${alt_testfile}"
remote_exec build "cp $binfile $binfile_3"
set symlink_2 "symlink_2"
with_cwd $reldir {
remote_exec build "ln -s ${alt_testfile} ${symlink_2}"
}
set work_dir [standard_output_file "workdir"]
remote_exec build "mkdir -p $work_dir"
set rel_path_to_file "../${reldir_name}/${alt_testfile}"
set rel_path_to_symlink_2 "../${reldir_name}/${symlink_2}"
with_cwd $work_dir {
with_test_prefix "to file" {
set corefile [core_find $rel_path_to_file]
if {$corefile == ""} {
untested "unable to create corefile"
return 0
}
set corefile_5 "${work_dir}/${testfile}.5.core"
remote_exec build "mv $corefile $corefile_5"
test_load $corefile_5 \
[file join $work_dir $rel_path_to_file] \
$rel_path_to_file
}
with_test_prefix "to symlink" {
set corefile [core_find $rel_path_to_symlink_2]
if {$corefile == ""} {
untested "unable to create corefile"
return 0
}
set corefile_6 "${work_dir}/${testfile}.6.core"
remote_exec build "mv $corefile $corefile_6"
test_load $corefile_6 \
[file join $work_dir $rel_path_to_symlink_2] \
$rel_path_to_symlink_2
}
# Move the core file. Now the relative path doesn't work so
# we instead rely on GDB to use information about the mapped
# files to help locate the executable.
with_test_prefix "with moved corefile" {
set corefile_7 [standard_output_file "${testfile}.7.core"]
remote_exec build "cp $corefile_6 $corefile_7"
test_load $corefile_7 $binfile_3 $rel_path_to_symlink_2
}
}
}