# Copyright 2019-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 . # Based on break.exp, written by Rob Savoye. (rob@cygnus.com) # Modified to test gdb's handling of separate debug info files. # Modified to test gdb's handling of a debug-id retrieval. # Build-id-related tests for core files. standard_testfile .c -shlib-shr.c -shlib.c # Create a corefile from PROGNAME. Return the name of the generated # corefile, or the empty string if anything goes wrong. # # The generated corefile must contain a buildid for PROGNAME. If it # doesn't then an empty string will be returned. proc create_core_file { progname } { # Generate a corefile. set corefile [core_find $progname] if {$corefile == ""} { untested "could not generate core file" return "" } verbose -log "corefile is $corefile" # Check the corefile has a build-id for the executable. if { [catch "exec [gdb_find_eu-unstrip] -n --core $corefile" output] == 0 } { set line [lindex [split $output "\n"] 0] set binfile_re (?:[string_to_regexp $progname]|\\\[(?:exe|pie)\\\]) if { ![regexp "^${::hex}\\+${::hex} \[a-f0-9\]+@${::hex}.*$binfile_re$" $line] } { unsupported "no build-id for executable in corefile" return "" } } else { unsupported "eu-unstrip tool failed" return "" } return $corefile } # Build a non-shared executable. proc build_corefile_buildid_exec { progname } { return [expr {[build_executable "build non-shared exec" $progname $::srcfile] != -1}] } # Build a shared executable. proc build_corefile_buildid_shared { progname } { # Compile DSO. set objdso [standard_output_file $::testfile-shlib-shr.so] if {[build_executable "build dso" $objdso $::srcfile2 {debug shlib}] == -1} { return false } # Compile shared library. set srclib $::srcfile3 set libname lib$::testfile.so set objlib [standard_output_file $libname] set dlopen_lib [shlib_target_file $objdso] set opts [list debug shlib_load shlib \ additional_flags=-DSHLIB_NAME=\"$dlopen_lib\"] if {[build_executable "build solib" $objlib $::srcfile3 $opts] == -1} { return false } # Compile main program. set opts [list debug shlib=$objlib additional_flags=-DTEST_SHARED] if {[build_executable "build shared exec" $progname $::srcfile $opts] == -1} { return false } return true } # Append DEBUGDIR to the debug-file-directory path. proc append_debug_dir {debugdir} { global gdb_prompt set orig_debugdir {} gdb_test_multiple "show debug-file-directory" \ "get debug-file-directory" { -re "The directory where separate debug symbols are searched for is \"(.*)\"\.\[\r\n\]+$gdb_prompt $" { set orig_debugdir $expect_out(1,string) pass "get debug-file-directory" } } gdb_test_no_output "set debug-file-directory $debugdir:$orig_debugdir" \ "append debug directory" } # A convenience procedure to check if "info files" mentions the exec file # FILE. proc check_exec_file {file} { global gdb_prompt send_log "expecting exec file \"$file\"\n" # Get line with "Local exec file:". set ok 0 gdb_test_multiple "info files" "" -lbl { -re "\r\nLocal exec file:" { set test_name $gdb_test_name set ok 1 } } if { $ok == 0 } { return } # Get subsequent line with $file. set ok 0 gdb_test_multiple "" $test_name -lbl { -re "\r\n\[\t\ \]+`[string_to_regexp $file]'\[^\r\n\]*" { set ok 1 } } if { $ok == 0 } { return } # Skip till prompt. gdb_test_multiple "" $test_name -lbl { -re "\r\n$gdb_prompt $" { pass $gdb_test_name } } } # Test whether gdb can find an exec file from a core file's build-id. # The executable (and separate debuginfo if SEPDEBUG is true) is # copied to the .build-id directory. # # SUFFIX is appended to the .builid-id parent directory name to # keep all tests separate. # SYMLINK specifies whether build-id files should be copied or symlinked. # SHARED is a boolean indicating whether we are testing the shared # library core dump test case. proc locate_exec_from_core_build_id {corefile buildid \ dirname progname \ sepdebug symlink shared} { clean_restart # Set up the build-id directory and symlink the binary there. set d "debugdir" if {$shared} { set d "${d}_shared" } else { set d "${d}_not-shared" } if {$symlink} { set d "${d}_symlink" } else { set d "${d}_copy" } if {$sepdebug} { set d "${d}_stripped" } else { set d "${d}_not-stripped" } set debugdir [standard_output_file $d] remote_exec build \ "mkdir -p [file join $debugdir [file dirname $buildid]]" set files_list {} lappend files_list [file join $dirname [file tail $progname]] \ $buildid if {$sepdebug} { lappend files_list [file join $dirname [file tail $progname]].debug \ "$buildid.debug" } foreach {target name} $files_list { set t [file join $dirname [file tail $target]] if {$symlink} { remote_exec build "ln -s $t [file join $debugdir $name]" } else { remote_exec build "cp $t [file join $debugdir $name]" } } # Append the debugdir to the separate debug directory search path. append_debug_dir $debugdir gdb_test "core-file $corefile" "Program terminated with .*" \ "load core file" if {$symlink} { set expected_file [file join $dirname [file tail $progname]] } else { set expected_file $buildid } check_exec_file [file join $debugdir $expected_file] } foreach_with_prefix mode { exec shared } { # Build the executable. set progname ${binfile}-$mode set build_proc build_corefile_buildid_${mode} if { ![$build_proc $progname] } { return -1 } # Generate a corefile. set corefile [create_core_file $progname] if { $corefile eq "" } { return -1 } # Get the build-id filename without ".debug" on the end. This # will have the format: '.build-id/xx/xxxxx' set buildid [build_id_debug_filename_get $progname ""] if {$buildid == ""} { untested "binary has no build-id" return } verbose -log "build-id is $buildid" # Create a directory for the non-stripped test. set combined_dirname [standard_output_file ${mode}_non-stripped] remote_exec build "mkdir -p $combined_dirname" remote_exec build "cp $progname $combined_dirname" # Create a directory for the stripped test. if {[gdb_gnu_strip_debug [standard_output_file $progname] no-debuglink] != 0} { untested "could not strip executable for [join $suffix \ ]" return } set sepdebug_dirname [standard_output_file ${mode}_stripped] remote_exec build "mkdir -p $sepdebug_dirname" remote_exec build "mv $progname $sepdebug_dirname" remote_exec build "mv ${progname}.debug $sepdebug_dirname" # Now do the actual testing part. Fill out a debug directory with # build-id related files (copies or symlinks) and then load the # corefile. Check GDB finds the executable and debug information # via the build-id related debug directory contents. foreach_with_prefix sepdebug { false true } { if { $sepdebug } { set dirname $sepdebug_dirname } else { set dirname $combined_dirname } foreach_with_prefix symlink { false true } { locate_exec_from_core_build_id $corefile $buildid \ $dirname $progname \ $sepdebug $symlink [expr {$mode eq "shared"}] } } }