| # Copyright 2024-2026 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/>. |
| |
| # Test the shadow stack pointer note in core dumps. |
| # Based on the corefile tests in gdb.arch/aarch64-gcs-core.exp. |
| |
| require allow_ssp_tests |
| |
| standard_testfile |
| |
| # Make sure GDB can read the given core file correctly. |
| |
| proc check_core_file {core_filename saved_pl3_ssp} { |
| global decimal |
| |
| # Load the core file. |
| if {[gdb_test "core $core_filename" \ |
| [multi_line \ |
| "Core was generated by .*\\." \ |
| "Program terminated with signal SIGSEGV, Segmentation fault.*" \ |
| "#0 function \\(\\) at .*amd64-shadow-stack-corefile.c:$decimal" \ |
| "$decimal.*__asm__ volatile \\(\"ret\\\\n\"\\);"] \ |
| "load core file"]} { |
| return |
| } |
| |
| # Check the value of ssp in the core file. |
| gdb_test "print/x \$pl3_ssp" "\\$\[0-9\]+ = $saved_pl3_ssp" \ |
| "pl3_ssp contents from core file" |
| } |
| |
| save_vars { ::env(GLIBC_TUNABLES) } { |
| |
| append_environment GLIBC_TUNABLES "glibc.cpu.hwcaps" "SHSTK" |
| |
| if { [prepare_for_testing "failed to prepare" $testfile $srcfile \ |
| {debug additional_flags="-fcf-protection=return"}] } { |
| return |
| } |
| |
| set linespec ${srcfile}:[gdb_get_line_number "Break here"] |
| |
| if {![runto $linespec]} { |
| return |
| } |
| |
| # Obtain an OS-generated core file. Save test program output to |
| # ${binfile}.out. |
| set core_filename [core_find $binfile {} {} "${binfile}.out"] |
| set core_generated [expr {$core_filename != ""}] |
| |
| if {!$core_generated} { |
| untested "unable to create or find corefile" |
| } |
| |
| # Load the core file and check the value of the shadow stack pointer. |
| if {$core_generated} { |
| clean_restart $::testfile |
| |
| with_test_prefix "OS corefile" { |
| # Read ssp value from saved output of the test program. |
| set out_id [open ${binfile}.out "r"] |
| set ssp_in_gcore [gets $out_id] |
| close $out_id |
| check_core_file $core_filename $ssp_in_gcore |
| } |
| } |
| |
| if {![gcore_cmd_available]} { |
| unsupported "target does not support gcore command." |
| return |
| } |
| |
| clean_restart $::testfile |
| |
| if {![runto $linespec]} { |
| return |
| } |
| |
| # Continue until a crash. The line with the hex number is optional because |
| # it's printed by the test program, and doesn't appear in the Expect buffer |
| # when testing a remote target. |
| |
| gdb_test "continue" \ |
| [multi_line \ |
| "Continuing\\." \ |
| "($hex\r\n)?" \ |
| "Program received signal SIGSEGV, Segmentation fault.*" \ |
| "function \\(\\) at .*amd64-shadow-stack-corefile.c:$decimal" \ |
| {.*__asm__ volatile \("ret\\n"\);}] \ |
| "continue to SIGSEGV" |
| |
| set ssp_in_gcore [get_valueof "/x" "\$pl3_ssp" "*unknown*"] |
| |
| # Generate the gcore core file. |
| set gcore_filename [standard_output_file "${testfile}.gcore"] |
| set gcore_generated [gdb_gcore_cmd "$gcore_filename" "generate gcore file"] |
| |
| gdb_assert { $gcore_generated } "gcore corefile created" |
| if { $gcore_generated } { |
| clean_restart $::testfile |
| |
| with_test_prefix "gcore corefile" { |
| check_core_file $gcore_filename $ssp_in_gcore |
| } |
| } |
| } |