aboutsummaryrefslogtreecommitdiff
path: root/gdb/testsuite/gdb.arch
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/testsuite/gdb.arch')
-rw-r--r--gdb/testsuite/gdb.arch/aarch64-gcs-core.c123
-rw-r--r--gdb/testsuite/gdb.arch/aarch64-gcs-core.exp113
-rw-r--r--gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.c140
-rw-r--r--gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.exp86
-rw-r--r--gdb/testsuite/gdb.arch/aarch64-gcs-return.c105
-rw-r--r--gdb/testsuite/gdb.arch/aarch64-gcs-return.exp129
-rw-r--r--gdb/testsuite/gdb.arch/aarch64-gcs-tdesc-without-linux.xml65
-rw-r--r--gdb/testsuite/gdb.arch/aarch64-gcs-wrong-tdesc.c26
-rw-r--r--gdb/testsuite/gdb.arch/aarch64-gcs-wrong-tdesc.exp48
-rw-r--r--gdb/testsuite/gdb.arch/aarch64-gcs.c180
-rw-r--r--gdb/testsuite/gdb.arch/aarch64-gcs.exp98
-rw-r--r--gdb/testsuite/gdb.arch/amd64-disp-step-avx.exp1
-rw-r--r--gdb/testsuite/gdb.arch/amd64-disp-step-self-call-alarm.c18
-rw-r--r--gdb/testsuite/gdb.arch/amd64-disp-step-self-call.S23
-rw-r--r--gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp143
-rw-r--r--gdb/testsuite/gdb.arch/amd64-shadow-stack-corefile.c46
-rw-r--r--gdb/testsuite/gdb.arch/amd64-shadow-stack-corefile.exp119
-rw-r--r--gdb/testsuite/gdb.arch/amd64-shadow-stack-disp-step.exp84
-rw-r--r--gdb/testsuite/gdb.arch/amd64-shadow-stack.c40
-rw-r--r--gdb/testsuite/gdb.arch/amd64-shadow-stack.exp71
-rw-r--r--gdb/testsuite/gdb.arch/amd64-watchpoint-downgrade.exp2
-rw-r--r--gdb/testsuite/gdb.arch/i386-disp-step-self-call-alarm.c18
-rw-r--r--gdb/testsuite/gdb.arch/i386-disp-step-self-call.S23
-rw-r--r--gdb/testsuite/gdb.arch/i386-prologue-skip-cf-protection-stackalign.c27
-rw-r--r--gdb/testsuite/gdb.arch/i386-prologue-skip-cf-protection.exp70
25 files changed, 1730 insertions, 68 deletions
diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs-core.c b/gdb/testsuite/gdb.arch/aarch64-gcs-core.c
new file mode 100644
index 0000000..7767204
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-gcs-core.c
@@ -0,0 +1,123 @@
+/* This test program is part of GDB, the GNU debugger.
+
+ Copyright 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 <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/auxv.h>
+#include <linux/prctl.h>
+#include <sys/syscall.h>
+
+/* Feature check for Guarded Control Stack. */
+#ifndef HWCAP_GCS
+#define HWCAP_GCS (1UL << 32)
+#endif
+
+#ifndef PR_GET_SHADOW_STACK_STATUS
+#define PR_GET_SHADOW_STACK_STATUS 74
+#define PR_SET_SHADOW_STACK_STATUS 75
+#define PR_SHADOW_STACK_ENABLE (1UL << 0)
+#endif
+
+/* We need to use a macro to call prctl because after GCS is enabled, it's not
+ possible to return from the function which enabled it. This is because the
+ return address of the calling function isn't on the GCS. */
+#define my_syscall2(num, arg1, arg2) \
+ ({ \
+ register long _num __asm__("x8") = (num); \
+ register long _arg1 __asm__("x0") = (long)(arg1); \
+ register long _arg2 __asm__("x1") = (long)(arg2); \
+ register long _arg3 __asm__("x2") = 0; \
+ register long _arg4 __asm__("x3") = 0; \
+ register long _arg5 __asm__("x4") = 0; \
+ \
+ __asm__ volatile ("svc #0\n" \
+ : "=r"(_arg1) \
+ : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \
+ "r"(_arg5), "r"(_num) \
+ : "memory", "cc"); \
+ _arg1; \
+ })
+
+#define get_gcspr(void) \
+ ({ \
+ unsigned long *gcspr; \
+ \
+ /* Get GCSPR_EL0. */ \
+ asm volatile ("mrs %0, S3_3_C2_C5_1" : "=r"(gcspr) : : "cc"); \
+ \
+ gcspr; \
+ })
+
+/* Corrupt the return address to see if GDB will report a SIGSEGV with the
+ expected $_siginfo.si_code. */
+static void __attribute__ ((noinline))
+function (unsigned long *gcspr)
+{
+ /* x30 holds the return address. */
+ register long x30 __asm__("x30") __attribute__ ((unused));
+
+ /* Print GCSPR to stdout so that the testcase can capture it. */
+ printf ("%p\n", get_gcspr ());
+ fflush (stdout);
+
+ /* Cause a GCS exception. */
+ x30 = 0xbadc0ffee;
+ __asm__ volatile ("ret\n");
+}
+
+int
+main (void)
+{
+ if (!(getauxval (AT_HWCAP) & HWCAP_GCS))
+ {
+ fprintf (stderr, "GCS support not found in AT_HWCAP\n");
+ return EXIT_FAILURE;
+ }
+
+ /* Force shadow stacks on, our tests *should* be fine with or
+ without libc support and with or without this having ended
+ up tagged for GCS and enabled by the dynamic linker. We
+ can't use the libc prctl() function since we can't return
+ from enabling the stack. Also lock GCS if not already
+ locked so we can test behaviour when it's locked. */
+ unsigned long gcs_mode;
+ int ret = my_syscall2 (__NR_prctl, PR_GET_SHADOW_STACK_STATUS, &gcs_mode);
+ if (ret)
+ {
+ fprintf (stderr, "Failed to read GCS state: %d\n", ret);
+ return EXIT_FAILURE;
+ }
+
+ if (!(gcs_mode & PR_SHADOW_STACK_ENABLE))
+ {
+ gcs_mode = PR_SHADOW_STACK_ENABLE;
+ ret = my_syscall2 (__NR_prctl, PR_SET_SHADOW_STACK_STATUS, gcs_mode);
+ if (ret)
+ {
+ fprintf (stderr, "Failed to configure GCS: %d\n", ret);
+ return EXIT_FAILURE;
+ }
+ }
+
+ unsigned long *gcspr = get_gcspr ();
+
+ /* Pass gscpr to function just so it's used for something. */
+ function (gcspr); /* Break here. */
+
+ /* Avoid returning, in case libc doesn't understand GCS. */
+ exit (EXIT_SUCCESS);
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs-core.exp b/gdb/testsuite/gdb.arch/aarch64-gcs-core.exp
new file mode 100644
index 0000000..2261ac8
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-gcs-core.exp
@@ -0,0 +1,113 @@
+# Copyright 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 <http://www.gnu.org/licenses/>.
+
+# Test reading and writing the core dump of a binary that uses a Guarded
+# Control Stack.
+
+require allow_aarch64_gcs_tests
+
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile] } {
+ 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 != ""}]
+
+# Make sure GDB can read the given core file correctly.
+proc check_core_file {core_filename saved_gcspr} {
+ global decimal hex
+
+ # Load the core file.
+ if [gdb_test "core $core_filename" \
+ [multi_line \
+ "Core was generated by .*\\." \
+ "Program terminated with signal SIGSEGV, Segmentation fault" \
+ "Guarded Control Stack error\\." \
+ "#0 function \\(gcspr=$hex\\) at .*aarch64-gcs-core.c:$decimal" \
+ "$decimal.*__asm__ volatile \\(\"ret\\\\n\"\\);"] \
+ "load core file"] {
+ return -1
+ }
+
+ # Check the value of GCSPR in the core file.
+ gdb_test "print/x \$gcspr" "\\$\[0-9\]+ = $saved_gcspr" \
+ "gcspr contents from core file"
+}
+
+if {!$core_generated} {
+ untested "unable to create or find corefile"
+}
+
+if {$core_generated} {
+ clean_restart $binfile
+
+ with_test_prefix "OS corefile" {
+ # Read GCSPR value from saved output of the test program.
+ set out_id [open ${binfile}.out "r"]
+ set gcspr_in_core [gets $out_id]
+ close $out_id
+
+ check_core_file $core_filename $gcspr_in_core
+ }
+}
+
+if ![gcore_cmd_available] {
+ unsupported "target does not support gcore command."
+ return
+}
+
+clean_restart $binfile
+
+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" \
+ "Guarded Control Stack error\\." \
+ "function \\(gcspr=$hex\\) at .*aarch64-gcs-core.c:$decimal" \
+ {.*__asm__ volatile \("ret\\n"\);}] \
+ "continue to SIGSEGV"
+
+set gcspr_in_gcore [get_valueof "/x" "\$gcspr" "*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 $binfile
+
+ with_test_prefix "gcore corefile" {
+ check_core_file $gcore_filename $gcspr_in_gcore
+ }
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.c b/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.c
new file mode 100644
index 0000000..3d89535
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.c
@@ -0,0 +1,140 @@
+/* This test program is part of GDB, the GNU debugger.
+
+ Copyright 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 <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/auxv.h>
+#include <sys/syscall.h>
+#include <linux/prctl.h>
+
+/* Feature check for Guarded Control Stack. */
+#ifndef HWCAP_GCS
+#define HWCAP_GCS (1UL << 32)
+#endif
+
+#ifndef PR_GET_SHADOW_STACK_STATUS
+#define PR_GET_SHADOW_STACK_STATUS 74
+#define PR_SET_SHADOW_STACK_STATUS 75
+#define PR_SHADOW_STACK_ENABLE (1UL << 0)
+#endif
+
+/* We need to use a macro to call prctl because after GCS is enabled, it's not
+ possible to return from the function which enabled it. This is because the
+ return address of the calling function isn't on the GCS. */
+#define my_syscall2(num, arg1, arg2) \
+ ({ \
+ register long _num __asm__("x8") = (num); \
+ register long _arg1 __asm__("x0") = (long)(arg1); \
+ register long _arg2 __asm__("x1") = (long)(arg2); \
+ register long _arg3 __asm__("x2") = 0; \
+ register long _arg4 __asm__("x3") = 0; \
+ register long _arg5 __asm__("x4") = 0; \
+ \
+ __asm__ volatile("svc #0\n" \
+ : "=r"(_arg1) \
+ : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \
+ "r"(_arg5), "r"(_num) \
+ : "memory", "cc"); \
+ _arg1; \
+ })
+
+#define get_gcspr(void) \
+ ({ \
+ unsigned long *gcspr; \
+ \
+ /* Get GCSPR_EL0. */ \
+ asm volatile("mrs %0, S3_3_C2_C5_1" : "=r"(gcspr) : : "cc"); \
+ \
+ gcspr; \
+ })
+
+static int __attribute__ ((noinline))
+function2 (void)
+{
+ return EXIT_SUCCESS;
+}
+
+/* Put branch and link instructions being tested into their own functions so
+ that the program returns one level up in the stack after the displaced
+ stepped instruction. This tests that GDB doesn't leave the GCS out of sync
+ with the regular stack. */
+
+static int __attribute__ ((noinline))
+function_bl (void)
+{
+ register int x0 __asm__("x0");
+
+ __asm__ ("bl function2\n"
+ : "=r"(x0)
+ :
+ : "x30");
+
+ return x0;
+}
+
+static int __attribute__ ((noinline))
+function_blr (void)
+{
+ register int x0 __asm__("x0");
+
+ __asm__ ("blr %1\n"
+ : "=r"(x0)
+ : "r"(&function2)
+ : "x30");
+
+ return x0;
+}
+
+int
+main (void)
+{
+ if (!(getauxval (AT_HWCAP) & HWCAP_GCS))
+ {
+ fprintf (stderr, "GCS support not found in AT_HWCAP\n");
+ return EXIT_FAILURE;
+ }
+
+ /* Force shadow stacks on, our tests *should* be fine with or
+ without libc support and with or without this having ended
+ up tagged for GCS and enabled by the dynamic linker. We
+ can't use the libc prctl() function since we can't return
+ from enabling the stack. */
+ unsigned long gcs_mode;
+ int ret = my_syscall2 (__NR_prctl, PR_GET_SHADOW_STACK_STATUS, &gcs_mode);
+ if (ret)
+ {
+ fprintf (stderr, "Failed to read GCS state: %d\n", ret);
+ return EXIT_FAILURE;
+ }
+
+ if (!(gcs_mode & PR_SHADOW_STACK_ENABLE))
+ {
+ gcs_mode = PR_SHADOW_STACK_ENABLE;
+ ret = my_syscall2 (__NR_prctl, PR_SET_SHADOW_STACK_STATUS, gcs_mode);
+ if (ret)
+ {
+ fprintf (stderr, "Failed to configure GCS: %d\n", ret);
+ return EXIT_FAILURE;
+ }
+ }
+
+ int ret1 = function_bl ();
+ int ret2 = function_blr ();
+
+ /* Avoid returning, in case libc doesn't understand GCS. */
+ exit (ret1 + ret2);
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.exp b/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.exp
new file mode 100644
index 0000000..2359d96
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.exp
@@ -0,0 +1,86 @@
+# Copyright 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 <http://www.gnu.org/licenses/>.
+
+# Test displaced stepping in a program that uses a Guarded Control Stack.
+
+require allow_aarch64_gcs_tests
+
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } {
+ return
+}
+
+if ![runto_main] {
+ return
+}
+
+gdb_test_no_output "set breakpoint auto-hw off"
+gdb_test_no_output "set displaced-stepping on"
+
+# Get address of the branch and link instructions of interest.
+set addr_bl 0
+set test "get address of bl instruction"
+gdb_test_multiple "disassemble function_bl" $test -lbl {
+ -re "\r\n\\s+($hex) <\\+${decimal}>:\\s+bl\\s+${hex} <function2>(?=\r\n)" {
+ set addr_bl $expect_out(1,string)
+ exp_continue
+ }
+ -re -wrap "" {
+ gdb_assert { $addr_bl != 0 } $test
+ }
+}
+
+set addr_blr 0
+set test "get address of blr instruction"
+gdb_test_multiple "disassemble function_blr" $test -lbl {
+ -re "\r\n\\s+($hex) <\\+${decimal}>:\\s+blr\\s+x${decimal}(?=\r\n)" {
+ set addr_blr $expect_out(1,string)
+ exp_continue
+ }
+ -re -wrap "" {
+ gdb_assert { $addr_blr != 0 } $test
+ }
+}
+
+if { $addr_bl == 0 || $addr_blr == 0 } {
+ return
+}
+
+gdb_test "break *$addr_bl" \
+ "Breakpoint $decimal at $hex: file .*aarch64-gcs-disp-step.c, line ${decimal}." \
+ "set breakpoint at bl instruction"
+
+gdb_test "break *$addr_blr" \
+ "Breakpoint $decimal at $hex: file .*aarch64-gcs-disp-step.c, line ${decimal}." \
+ "set breakpoint at blr instruction"
+
+gdb_test "continue" \
+ [multi_line \
+ {Continuing\.} \
+ "" \
+ "Breakpoint $decimal, function_bl \\(\\) at .*aarch64-gcs-disp-step.c:${decimal}(?: \\\[GCS error\\\])?" \
+ {[^\r\n]+"bl function2\\n"}] \
+ "continue to breakpoint at bl"
+
+gdb_test "continue" \
+ [multi_line \
+ {Continuing\.} \
+ "" \
+ "Breakpoint $decimal, $hex in function_blr \\(\\) at .*aarch64-gcs-disp-step.c:${decimal}(?: \\\[GCS error\\\])?" \
+ {[^\r\n]+"blr %1\\n"}] \
+ "continue to breakpoint at blr"
+
+gdb_continue_to_end
diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs-return.c b/gdb/testsuite/gdb.arch/aarch64-gcs-return.c
new file mode 100644
index 0000000..95518b6
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-gcs-return.c
@@ -0,0 +1,105 @@
+/* This test program is part of GDB, the GNU debugger.
+
+ Copyright 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 <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/auxv.h>
+#include <sys/syscall.h>
+#include <linux/prctl.h>
+
+/* Feature check for Guarded Control Stack. */
+#ifndef HWCAP_GCS
+#define HWCAP_GCS (1UL << 32)
+#endif
+
+#ifndef PR_GET_SHADOW_STACK_STATUS
+#define PR_GET_SHADOW_STACK_STATUS 74
+#define PR_SET_SHADOW_STACK_STATUS 75
+#define PR_SHADOW_STACK_ENABLE (1UL << 0)
+#endif
+
+/* We need to use a macro to call prctl because after GCS is enabled, it's not
+ possible to return from the function which enabled it. This is because the
+ return address of the calling function isn't on the GCS. */
+#define my_syscall2(num, arg1, arg2) \
+ ({ \
+ register long _num __asm__("x8") = (num); \
+ register long _arg1 __asm__("x0") = (long)(arg1); \
+ register long _arg2 __asm__("x1") = (long)(arg2); \
+ register long _arg3 __asm__("x2") = 0; \
+ register long _arg4 __asm__("x3") = 0; \
+ register long _arg5 __asm__("x4") = 0; \
+ \
+ __asm__ volatile("svc #0\n" \
+ : "=r"(_arg1) \
+ : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \
+ "r"(_arg5), "r"(_num) \
+ : "memory", "cc"); \
+ _arg1; \
+ })
+
+static int __attribute__ ((noinline))
+call2 ()
+{
+ return 42; /* Break call2. */
+}
+
+static int __attribute__ ((noinline))
+call1 ()
+{
+ return call2 (); /* Break call1. */
+}
+
+int
+main ()
+{
+ if (!(getauxval (AT_HWCAP) & HWCAP_GCS))
+ {
+ fprintf (stderr, "GCS support not found in AT_HWCAP\n");
+ return EXIT_FAILURE;
+ }
+
+ /* Force shadow stacks on, our tests *should* be fine with or
+ without libc support and with or without this having ended
+ up tagged for GCS and enabled by the dynamic linker. We
+ can't use the libc prctl() function since we can't return
+ from enabling the stack. Also lock GCS if not already
+ locked so we can test behaviour when it's locked. */
+ unsigned long gcs_mode;
+ int ret = my_syscall2 (__NR_prctl, PR_GET_SHADOW_STACK_STATUS, &gcs_mode);
+ if (ret)
+ {
+ fprintf (stderr, "Failed to read GCS state: %d\n", ret);
+ return EXIT_FAILURE;
+ }
+
+ if (!(gcs_mode & PR_SHADOW_STACK_ENABLE))
+ {
+ gcs_mode = PR_SHADOW_STACK_ENABLE;
+ ret = my_syscall2 (__NR_prctl, PR_SET_SHADOW_STACK_STATUS, gcs_mode);
+ if (ret)
+ {
+ fprintf (stderr, "Failed to configure GCS: %d\n", ret);
+ return EXIT_FAILURE;
+ }
+ }
+
+ call1 (); /* Break begin. */
+
+ /* Avoid returning, in case libc doesn't understand GCS. */
+ exit (EXIT_SUCCESS);
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs-return.exp b/gdb/testsuite/gdb.arch/aarch64-gcs-return.exp
new file mode 100644
index 0000000..1d1c237
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-gcs-return.exp
@@ -0,0 +1,129 @@
+# Copyright 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 <http://www.gnu.org/licenses/>.
+
+# Test the GDB return command in a program that uses a Guarded Control Stack.
+# Based on the return tests in gdb.arch/amd64-shadow-stack-cmds.exp.
+# Note that potential GCS violations often only occur after resuming normal
+# execution. Therefore, it is important to test normal program
+# completion after testing the return command.
+
+require allow_aarch64_gcs_tests
+
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } {
+ return
+}
+
+set begin_line [gdb_get_line_number "Break begin"]
+set call1_line [gdb_get_line_number "Break call1"]
+set call2_line [gdb_get_line_number "Break call2"]
+
+if ![runto ${begin_line}] {
+ return
+}
+
+proc restart_and_run_infcall_call2 {} {
+ global binfile call2_line
+ clean_restart ${binfile}
+ if ![runto_main] {
+ return
+ }
+ set inside_infcall_str "The program being debugged stopped while in a function called from GDB"
+ gdb_breakpoint ${call2_line}
+ gdb_continue_to_breakpoint "Break call2" ".*Break call2.*"
+ gdb_test "call (int) call2()" \
+ "Breakpoint \[0-9\]*, call2.*$inside_infcall_str.*"
+}
+
+with_test_prefix "test inferior call and continue" {
+ gdb_breakpoint ${call1_line}
+ gdb_continue_to_breakpoint "Break call1" ".*Break call1.*"
+
+ gdb_test "call (int) call2()" "= 42"
+
+ gdb_continue_to_end
+}
+
+with_test_prefix "test return inside an inferior call" {
+ restart_and_run_infcall_call2
+
+ gdb_test "return" "\#0.*call2.*" \
+ "Test GCS return inside an inferior call" \
+ "Make.*return now\\? \\(y or n\\) " "y"
+
+ gdb_continue_to_end
+}
+
+with_test_prefix "test return 'above' an inferior call" {
+ restart_and_run_infcall_call2
+
+ gdb_test "frame 2" "call2 ().*" "move to frame 'above' inferior call"
+
+ gdb_test "return" "\#0.*call1.*" \
+ "Test GCS return 'above' an inferior call" \
+ "Make.*return now\\? \\(y or n\\) " "y"
+
+ gdb_continue_to_end
+}
+
+clean_restart ${binfile}
+if ![runto ${begin_line}] {
+ return
+}
+
+# Extract GCS pointer inside main, call1 and call2 function.
+gdb_breakpoint ${call1_line}
+gdb_breakpoint ${call2_line}
+set gcspr_main [get_valueof /x "\$gcspr" 0 "get value of gcspr in main"]
+gdb_continue_to_breakpoint "Break call1" ".*Break call1.*"
+set gcspr_call1 [get_valueof /x "\$gcspr" 0 "get value of gcspr in call1"]
+gdb_continue_to_breakpoint "Break call2" ".*Break call2.*"
+set gcspr_call2 [get_valueof /x "\$gcspr" 0 "get value of gcspr in call2"]
+
+with_test_prefix "test frame level update" {
+ gdb_test "up" "call1.*" "move to frame 1"
+ gdb_test "print /x \$gcspr" "= $gcspr_call1" "check gcspr of frame 1"
+ gdb_test "up" "main.*" "move to frame 2"
+ gdb_test "print /x \$gcspr" "= $gcspr_main" "check gcspr of frame 2"
+ gdb_test "frame 0" "call2.*" "move to frame 0"
+ gdb_test "print /x \$gcspr" "= $gcspr_call2" "check gcspr of frame 0"
+}
+
+with_test_prefix "test return from current frame" {
+ gdb_test "return (int) 1" "#0.*call1.*" \
+ "Test GCS return from current frame" \
+ "Make.*return now\\? \\(y or n\\) " "y"
+
+ gdb_continue_to_end
+}
+
+clean_restart ${binfile}
+if ![runto_main] {
+ return
+}
+
+with_test_prefix "test return from past frame" {
+ gdb_breakpoint ${call2_line}
+ gdb_continue_to_breakpoint "Break call2" ".*Break call2.*"
+
+ gdb_test "frame 1" ".*in call1.*"
+
+ gdb_test "return (int) 1" "#0.*main.*" \
+ "Test GCS return from past frame" \
+ "Make.*return now\\? \\(y or n\\) " "y"
+
+ gdb_continue_to_end
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs-tdesc-without-linux.xml b/gdb/testsuite/gdb.arch/aarch64-gcs-tdesc-without-linux.xml
new file mode 100644
index 0000000..056ab58
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-gcs-tdesc-without-linux.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0"?>
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target>
+ <architecture>aarch64</architecture>
+ <feature name="org.gnu.gdb.aarch64.core">
+ <flags id="cpsr_flags" size="4">
+ <field name="SP" start="0" end="0" type="bool"/>
+ <field name="EL" start="2" end="3" type="uint32"/>
+ <field name="nRW" start="4" end="4" type="bool"/>
+ <field name="F" start="6" end="6" type="bool"/>
+ <field name="I" start="7" end="7" type="bool"/>
+ <field name="A" start="8" end="8" type="bool"/>
+ <field name="D" start="9" end="9" type="bool"/>
+ <field name="BTYPE" start="10" end="11" type="uint32"/>
+ <field name="SSBS" start="12" end="12" type="bool"/>
+ <field name="IL" start="20" end="20" type="bool"/>
+ <field name="SS" start="21" end="21" type="bool"/>
+ <field name="PAN" start="22" end="22" type="bool"/>
+ <field name="UAO" start="23" end="23" type="bool"/>
+ <field name="DIT" start="24" end="24" type="bool"/>
+ <field name="TCO" start="25" end="25" type="bool"/>
+ <field name="V" start="28" end="28" type="bool"/>
+ <field name="C" start="29" end="29" type="bool"/>
+ <field name="Z" start="30" end="30" type="bool"/>
+ <field name="N" start="31" end="31" type="bool"/>
+ </flags>
+ <reg name="x0" bitsize="64" type="int" regnum="0"/>
+ <reg name="x1" bitsize="64" type="int" regnum="1"/>
+ <reg name="x2" bitsize="64" type="int" regnum="2"/>
+ <reg name="x3" bitsize="64" type="int" regnum="3"/>
+ <reg name="x4" bitsize="64" type="int" regnum="4"/>
+ <reg name="x5" bitsize="64" type="int" regnum="5"/>
+ <reg name="x6" bitsize="64" type="int" regnum="6"/>
+ <reg name="x7" bitsize="64" type="int" regnum="7"/>
+ <reg name="x8" bitsize="64" type="int" regnum="8"/>
+ <reg name="x9" bitsize="64" type="int" regnum="9"/>
+ <reg name="x10" bitsize="64" type="int" regnum="10"/>
+ <reg name="x11" bitsize="64" type="int" regnum="11"/>
+ <reg name="x12" bitsize="64" type="int" regnum="12"/>
+ <reg name="x13" bitsize="64" type="int" regnum="13"/>
+ <reg name="x14" bitsize="64" type="int" regnum="14"/>
+ <reg name="x15" bitsize="64" type="int" regnum="15"/>
+ <reg name="x16" bitsize="64" type="int" regnum="16"/>
+ <reg name="x17" bitsize="64" type="int" regnum="17"/>
+ <reg name="x18" bitsize="64" type="int" regnum="18"/>
+ <reg name="x19" bitsize="64" type="int" regnum="19"/>
+ <reg name="x20" bitsize="64" type="int" regnum="20"/>
+ <reg name="x21" bitsize="64" type="int" regnum="21"/>
+ <reg name="x22" bitsize="64" type="int" regnum="22"/>
+ <reg name="x23" bitsize="64" type="int" regnum="23"/>
+ <reg name="x24" bitsize="64" type="int" regnum="24"/>
+ <reg name="x25" bitsize="64" type="int" regnum="25"/>
+ <reg name="x26" bitsize="64" type="int" regnum="26"/>
+ <reg name="x27" bitsize="64" type="int" regnum="27"/>
+ <reg name="x28" bitsize="64" type="int" regnum="28"/>
+ <reg name="x29" bitsize="64" type="int" regnum="29"/>
+ <reg name="x30" bitsize="64" type="int" regnum="30"/>
+ <reg name="sp" bitsize="64" type="data_ptr" regnum="31"/>
+ <reg name="pc" bitsize="64" type="code_ptr" regnum="32"/>
+ <reg name="cpsr" bitsize="32" type="cpsr_flags" regnum="33"/>
+ </feature>
+ <feature name="org.gnu.gdb.aarch64.gcs">
+ <reg name="gcspr" bitsize="64" type="data_ptr" regnum="90" group="system"/>
+ </feature>
+</target>
diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs-wrong-tdesc.c b/gdb/testsuite/gdb.arch/aarch64-gcs-wrong-tdesc.c
new file mode 100644
index 0000000..10cf749
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-gcs-wrong-tdesc.c
@@ -0,0 +1,26 @@
+/* This test program is part of GDB, the GNU debugger.
+
+ Copyright 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 <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+
+int
+main (void)
+{
+ printf ("Hello, world!\n");
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs-wrong-tdesc.exp b/gdb/testsuite/gdb.arch/aarch64-gcs-wrong-tdesc.exp
new file mode 100644
index 0000000..f0508cd
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-gcs-wrong-tdesc.exp
@@ -0,0 +1,48 @@
+# Copyright 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 <http://www.gnu.org/licenses/>.
+
+# Test that GDB complains when given a target description with the GCS feature
+# but not the GCS Linux feature.
+
+require allow_aarch64_gcs_tests
+
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } {
+ return
+}
+
+set xml_path "${srcdir}/${subdir}/aarch64-gcs-tdesc-without-linux.xml"
+
+gdb_test "set tdesc filename ${xml_path}" \
+ "warning: Incomplete GCS support in the target: missing Linux part. GCS feature disabled." \
+ "warn about incomplete GCS support"
+
+# We can't test a debugging session on a remote target because with the
+# wrong tdesc, GDB expects a g packet reply with the wrong size.
+if {[gdb_protocol_is_remote]} {
+ return
+}
+
+if ![runto_main] {
+ return
+}
+
+gdb_test "print \$gcspr" " = <unavailable>" "GCSPR is unavailable"
+
+# Now check that we can continue the debugging session normally.
+gdb_test "next"
+
+gdb_continue_to_end
diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs.c b/gdb/testsuite/gdb.arch/aarch64-gcs.c
new file mode 100644
index 0000000..39519e4
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-gcs.c
@@ -0,0 +1,180 @@
+/* This test program is part of GDB, the GNU debugger.
+
+ Copyright 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 <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/auxv.h>
+#include <sys/syscall.h>
+#include <linux/prctl.h>
+
+/* Feature check for Guarded Control Stack. */
+#ifndef HWCAP_GCS
+#define HWCAP_GCS (1UL << 32)
+#endif
+
+#ifndef PR_GET_SHADOW_STACK_STATUS
+#define PR_GET_SHADOW_STACK_STATUS 74
+#define PR_SET_SHADOW_STACK_STATUS 75
+#define PR_SHADOW_STACK_ENABLE (1UL << 0)
+#endif
+
+/* We need to use a macro to call prctl because after GCS is enabled, it's not
+ possible to return from the function which enabled it. This is because the
+ return address of the calling function isn't on the GCS. */
+#define my_syscall2(num, arg1, arg2) \
+ ({ \
+ register long _num __asm__("x8") = (num); \
+ register long _arg1 __asm__("x0") = (long)(arg1); \
+ register long _arg2 __asm__("x1") = (long)(arg2); \
+ register long _arg3 __asm__("x2") = 0; \
+ register long _arg4 __asm__("x3") = 0; \
+ register long _arg5 __asm__("x4") = 0; \
+ \
+ __asm__ volatile ("svc #0\n" \
+ : "=r"(_arg1) \
+ : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \
+ "r"(_arg5), "r"(_num) \
+ : "memory", "cc"); \
+ _arg1; \
+ })
+
+#define get_gcspr(void) \
+ ({ \
+ unsigned long *gcspr; \
+ \
+ /* Get GCSPR_EL0. */ \
+ asm volatile ("mrs %0, S3_3_C2_C5_1" : "=r"(gcspr) : : "cc"); \
+ \
+ gcspr; \
+ })
+
+static unsigned long *handler_gcspr = 0;
+
+static void
+handler (int sig)
+{
+ handler_gcspr = get_gcspr ();
+}
+
+static int __attribute__ ((unused))
+called_from_gdb (int val)
+{
+ return val + 1;
+}
+
+/* Corrupt the return address to see if GDB will report a SIGSEGV with the
+ expected $_siginfo.si_code. */
+static void __attribute__ ((noinline))
+normal_function2 (void)
+{
+ /* x30 holds the return address. */
+ register unsigned long x30 __asm__("x30") __attribute__ ((unused));
+
+ /* Cause a GCS exception. */
+ x30 = 0xbadc0ffee;
+ /* Use explicit ret so that we can verify that a SIGSEGV was generated
+ exactly on the return instruction. */
+ __asm__ volatile ("ret\n");
+}
+
+static inline void __attribute__ ((__always_inline__))
+inline_function2 (void)
+{
+ normal_function2 ();
+}
+
+static void __attribute__ ((noinline))
+normal_function1 (void)
+{
+ inline_function2 ();
+}
+
+/* First in a sequence of inline and normal functions, to test GDB
+ backtrace. */
+static inline void __attribute__ ((__always_inline__))
+inline_function1 (void)
+{
+ normal_function1 ();
+}
+
+/* Trivial function, just so that GDB can test return with wrong GCSPR. */
+static void __attribute__ ((noinline))
+normal_function0 (void)
+{
+ /* Use explicit ret so that we can verify that a SIGSEGV was generated
+ exactly on the return instruction. */
+ __asm__ volatile ("ret\n");
+}
+
+int
+main (void)
+{
+ if (!(getauxval (AT_HWCAP) & HWCAP_GCS))
+ {
+ fprintf (stderr, "GCS support not found in AT_HWCAP\n");
+ return EXIT_FAILURE;
+ }
+
+ /* Force shadow stacks on, our tests *should* be fine with or
+ without libc support and with or without this having ended
+ up tagged for GCS and enabled by the dynamic linker. We
+ can't use the libc prctl() function since we can't return
+ from enabling the stack. Also lock GCS if not already
+ locked so we can test behaviour when it's locked. */
+ unsigned long gcs_mode;
+ int ret = my_syscall2 (__NR_prctl, PR_GET_SHADOW_STACK_STATUS, &gcs_mode);
+ if (ret)
+ {
+ fprintf (stderr, "Failed to read GCS state: %d\n", ret);
+ return EXIT_FAILURE;
+ }
+
+ if (!(gcs_mode & PR_SHADOW_STACK_ENABLE))
+ {
+ gcs_mode = PR_SHADOW_STACK_ENABLE;
+ ret = my_syscall2 (__NR_prctl, PR_SET_SHADOW_STACK_STATUS, gcs_mode);
+ if (ret)
+ {
+ fprintf (stderr, "Failed to configure GCS: %d\n", ret);
+ return EXIT_FAILURE;
+ }
+ }
+
+ /* Regular function call. */
+ normal_function0 ();
+
+ /* This is used by GDB. */
+ __attribute__((unused)) unsigned long *gcspr = get_gcspr ();
+
+ struct sigaction act = { 0 };
+
+ act.sa_handler = &handler; /* Break here. */
+ if (sigaction (SIGUSR1, &act, NULL) == -1)
+ {
+ perror ("sigaction");
+ exit (EXIT_FAILURE);
+ }
+
+ raise (SIGUSR1);
+
+/* Call sequence of inline and normal functions, to test GDB backtrace. */
+ inline_function1 ();
+
+ /* Avoid returning, in case libc doesn't understand GCS. */
+ exit (EXIT_SUCCESS);
+}
diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs.exp b/gdb/testsuite/gdb.arch/aarch64-gcs.exp
new file mode 100644
index 0000000..ad73b41
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/aarch64-gcs.exp
@@ -0,0 +1,98 @@
+# Copyright 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 <http://www.gnu.org/licenses/>.
+
+# Test a binary that uses a Guarded Control Stack.
+
+require allow_aarch64_gcs_tests
+
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } {
+ return
+}
+
+set linespec ${srcfile}:[gdb_get_line_number "Break here"]
+
+if ![runto ${linespec}] {
+ return
+}
+
+gdb_test "print \$gcs_features_enabled" \
+ [string_to_regexp { = [ PR_SHADOW_STACK_ENABLE ]}] \
+ "GCS is enabled"
+
+gdb_test "print \$gcspr" ". = \\(void \\*\\) $hex" "GDB knows about gcspr"
+gdb_test "print \$gcspr == gcspr" ". = 1" "GDB has the correct gcspr value"
+gdb_test_no_output "set \$gcspr_in_main = \$gcspr" \
+ "save gcspr value in main for later"
+
+# If the inferior function call fails, we don't want the tests following it
+# to be affected.
+gdb_test_no_output "set unwindonsignal on"
+gdb_test "print called_from_gdb (41)" ". = 42" "call inferior function"
+
+gdb_test "break handler" "Breakpoint \[0-9\]+ .*aarch64-gcs.c, line \[0-9\]+\\."
+gdb_test "handle SIGUSR1 nostop" \
+ ".*\r\nSIGUSR1\\s+No\\s+Yes\\s+Yes\\s+User defined signal 1" \
+ "let the inferior receive SIGUSR1 uninterrupted"
+gdb_test "continue" \
+ ".*\r\nBreakpoint \[0-9\]+, handler \\(sig=10\\) at .*aarch64-gcs.c.*handler_gcspr = get_gcspr \\(\\);" \
+ "continue to signal handler"
+
+gdb_test_no_output "set \$gcspr_in_handler = \$gcspr" \
+ "save gcspr value in handler for later"
+# Select the frame above the <signal handler called> frame, which makes GDB
+# unwind the gcspr from the signal frame GCS context.
+gdb_test "frame 2" "#2 ($hex in )?\\S+ \\(.*\\) (at|from) \\S+.*" \
+ "reached frame 2"
+gdb_test "print \$gcspr" ". = \\(void \\*\\) $hex" "gcspr in frame level 2"
+gdb_test "print \$gcspr == \$gcspr_in_handler + 8" ". = 1" \
+ "gcspr unwound from signal context is correct"
+
+gdb_test "continue" \
+ [multi_line \
+ "Continuing\\." \
+ "" \
+ "Program received signal SIGSEGV, Segmentation fault" \
+ "Guarded Control Stack error\\." \
+ "normal_function2 \\(\\) at .*aarch64-gcs.c:$decimal" \
+ "${decimal}\\s+__asm__ volatile \\(\"ret\\\\n\"\\);"] \
+ "continue to SIGSEGV"
+
+gdb_test "print \$_siginfo.si_code" ". = 10" \
+ "test value of si_code when GCS SIGSEGV happens"
+# The GCS grows down, and there are two real frames until main.
+gdb_test "print \$gcspr == \$gcspr_in_main - 16" ". = 1" \
+ "test value of gcspr when GCS SIGSEGV happens"
+
+# Test writing to GCSPR.
+clean_restart ${binfile}
+if ![runto normal_function0] {
+ return
+}
+
+gdb_test_no_output "set \$gcspr = 0xbadc0ffee" "set bogus gcspr value"
+# Continue to make sure that the value was actually written to the register.
+# The SIGSEGV isn't a GCS error because the problem isn't that the GCS entry
+# doesn't match the return address, but rather that that GCSPR is pointing
+# to an invalid address.
+gdb_test "continue" \
+ [multi_line \
+ "Continuing\\." \
+ "" \
+ "Program received signal SIGSEGV, Segmentation fault\\." \
+ "normal_function0 \\(\\) at .*aarch64-gcs.c:$decimal" \
+ "${decimal}\\s+__asm__ volatile \\(\"ret\\\\n\"\\);"] \
+ "continue after bad gcspr"
diff --git a/gdb/testsuite/gdb.arch/amd64-disp-step-avx.exp b/gdb/testsuite/gdb.arch/amd64-disp-step-avx.exp
index 08d73d8..b11efa7 100644
--- a/gdb/testsuite/gdb.arch/amd64-disp-step-avx.exp
+++ b/gdb/testsuite/gdb.arch/amd64-disp-step-avx.exp
@@ -19,6 +19,7 @@
# instructions.
require is_x86_64_m64_target have_avx
+require support_displaced_stepping
standard_testfile .S
diff --git a/gdb/testsuite/gdb.arch/amd64-disp-step-self-call-alarm.c b/gdb/testsuite/gdb.arch/amd64-disp-step-self-call-alarm.c
index 03b868c..0fb2904 100644
--- a/gdb/testsuite/gdb.arch/amd64-disp-step-self-call-alarm.c
+++ b/gdb/testsuite/gdb.arch/amd64-disp-step-self-call-alarm.c
@@ -16,9 +16,27 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <unistd.h>
+#include <stdlib.h>
+
+extern void test_call (void);
+
+void
+unreachable (void)
+{
+ abort ();
+}
void
setup_alarm (void)
{
alarm (300);
}
+
+int
+main ()
+{
+ setup_alarm ();
+ test_call ();
+ unreachable ();
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/amd64-disp-step-self-call.S b/gdb/testsuite/gdb.arch/amd64-disp-step-self-call.S
index 78a6859..20a8eb7 100644
--- a/gdb/testsuite/gdb.arch/amd64-disp-step-self-call.S
+++ b/gdb/testsuite/gdb.arch/amd64-disp-step-self-call.S
@@ -18,33 +18,12 @@
handling. */
.text
-
- .global main
-main:
- nop
-
- callq setup_alarm
-
- nop
-
-/***********************************************/
-
-/* test call/ret */
-
.global test_call
test_call:
call test_call
- nop
+ call unreachable
.global test_ret_end
test_ret_end:
nop
-/***********************************************/
-
-/* all done */
-
-done:
- mov $0,%rdi
- call exit
- hlt
.section .note.GNU-stack,"",@progbits
diff --git a/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp b/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp
new file mode 100644
index 0000000..c819cbc
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-shadow-stack-cmds.exp
@@ -0,0 +1,143 @@
+# 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 <http://www.gnu.org/licenses/>.
+
+# Test shadow stack enabling for frame level update, the return and the
+# call commands.
+# As potential CET violations often only occur after resuming normal
+# execution, test normal program continuation after each return or call
+# commands.
+
+require allow_ssp_tests
+
+standard_testfile amd64-shadow-stack.c
+
+# Restart GDB an run until breakpoint in call2.
+
+proc restart_and_run_infcall_call2 {} {
+ global binfile
+ clean_restart ${binfile}
+ if { ![runto_main] } {
+ return -1
+ }
+ set inside_infcall_str "The program being debugged stopped while in a function called from GDB"
+ gdb_breakpoint [ gdb_get_line_number "break call2" ]
+ gdb_continue_to_breakpoint "break call2" ".*break call2.*"
+ gdb_test "call (int) call2()" \
+ "Breakpoint \[0-9\]*, call2.*$inside_infcall_str.*"
+}
+
+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 -1
+ }
+
+ clean_restart ${binfile}
+ if { ![runto_main] } {
+ return -1
+ }
+
+ with_test_prefix "test inferior call and continue" {
+ gdb_breakpoint [ gdb_get_line_number "break call1" ]
+ gdb_continue_to_breakpoint "break call1" ".*break call1.*"
+
+ gdb_test "call (int) call2()" "= 42"
+
+ gdb_continue_to_end
+ }
+
+ with_test_prefix "test return inside an inferior call" {
+ restart_and_run_infcall_call2
+
+ gdb_test "return" "\#0.*call2.*" \
+ "Test shadow stack return inside an inferior call" \
+ "Make.*return now\\? \\(y or n\\) " "y"
+
+ gdb_continue_to_end
+ }
+
+ with_test_prefix "test return 'above' an inferior call" {
+ restart_and_run_infcall_call2
+
+ gdb_test "frame 2" "call2 ().*" "move to frame 'above' inferior call"
+
+ gdb_test "return" "\#0.*call1.*" \
+ "Test shadow stack return 'above' an inferior call" \
+ "Make.*return now\\? \\(y or n\\) " "y"
+
+ gdb_continue_to_end
+ }
+
+ clean_restart ${binfile}
+ if { ![runto_main] } {
+ return -1
+ }
+
+ set call1_line [ gdb_get_line_number "break call1" ]
+ set call2_line [ gdb_get_line_number "break call2" ]
+
+ # Extract shadow stack pointer inside main, call1 and call2 function.
+ gdb_breakpoint $call1_line
+ gdb_breakpoint $call2_line
+ set ssp_main [get_valueof /x "\$pl3_ssp" 0 "get value of ssp in main"]
+ gdb_continue_to_breakpoint "break call1" ".*break call1.*"
+ set ssp_call1 [get_valueof /x "\$pl3_ssp" 0 "get value of ssp in call1"]
+ gdb_continue_to_breakpoint "break call2" ".*break call2.*"
+ set ssp_call2 [get_valueof /x "\$pl3_ssp" 0 "get value of ssp in call2"]
+
+ with_test_prefix "test frame level update" {
+ gdb_test "up" "call1.*" "move to frame 1"
+ gdb_test "print /x \$pl3_ssp" "= $ssp_call1" "check pl3_ssp of frame 1"
+ gdb_test "up" "main.*" "move to frame 2"
+ gdb_test "print /x \$pl3_ssp" "= $ssp_main" "check pl3_ssp of frame 2"
+ gdb_test "frame 0" "call2.*" "move to frame 0"
+ gdb_test "print /x \$pl3_ssp" "= $ssp_call2" "check pl3_ssp of frame 0"
+ }
+
+ with_test_prefix "test return from current frame" {
+ gdb_test "return (int) 1" "#0.*call1.*" \
+ "Test shadow stack return from current frame" \
+ "Make.*return now\\? \\(y or n\\) " "y"
+
+ # Potential CET violations often only occur after resuming normal execution.
+ # Therefore, it is important to test normal program continuation after
+ # testing the return command.
+ gdb_continue_to_end
+ }
+
+ clean_restart ${binfile}
+ if { ![runto_main] } {
+ return -1
+ }
+
+ with_test_prefix "test return from past frame" {
+ gdb_breakpoint $call2_line
+ gdb_continue_to_breakpoint "break call2" ".*break call2.*"
+
+ gdb_test "frame 1" ".*in call1.*"
+
+ gdb_test "return (int) 1" "#0.*main.*" \
+ "Test shadow stack return from past frame" \
+ "Make.*return now\\? \\(y or n\\) " "y"
+
+ # Potential CET violations often only occur after resuming normal execution.
+ # Therefore, it is important to test normal program continuation after
+ # testing the return command.
+ gdb_continue_to_end
+ }
+}
diff --git a/gdb/testsuite/gdb.arch/amd64-shadow-stack-corefile.c b/gdb/testsuite/gdb.arch/amd64-shadow-stack-corefile.c
new file mode 100644
index 0000000..5e84793
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-shadow-stack-corefile.c
@@ -0,0 +1,46 @@
+/* This test program is part of GDB, the GNU debugger.
+
+ Copyright 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 <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+
+/* Call the return instruction before function epilogue to trigger a
+ control-flow exception. */
+void
+function ()
+{
+ unsigned long ssp;
+ #ifndef __ILP32__
+ asm volatile ("xor %0, %0; rdsspq %0" : "=r" (ssp));
+ #else
+ asm volatile ("xor %0, %0; rdsspd %0" : "=r" (ssp));
+ #endif
+
+ /* Print ssp to stdout so that the testcase can capture it. */
+ printf ("%p\n", (void *) ssp);
+ fflush (stdout);
+
+ /* Manually cause a control-flow exception by executing a return
+ instruction before function epilogue, so the address atop the stack
+ is not the return instruction. */
+ __asm__ volatile ("ret\n");
+}
+
+int
+main (void)
+{
+ function (); /* Break here. */
+}
diff --git a/gdb/testsuite/gdb.arch/amd64-shadow-stack-corefile.exp b/gdb/testsuite/gdb.arch/amd64-shadow-stack-corefile.exp
new file mode 100644
index 0000000..a45cd06
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-shadow-stack-corefile.exp
@@ -0,0 +1,119 @@
+# 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 <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 $saved_pl3_ssp"
+}
+
+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 $binfile
+
+ 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 $binfile
+
+ 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 $binfile
+
+ with_test_prefix "gcore corefile" {
+ check_core_file $gcore_filename $ssp_in_gcore
+ }
+ }
+}
diff --git a/gdb/testsuite/gdb.arch/amd64-shadow-stack-disp-step.exp b/gdb/testsuite/gdb.arch/amd64-shadow-stack-disp-step.exp
new file mode 100644
index 0000000..e4efa00
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-shadow-stack-disp-step.exp
@@ -0,0 +1,84 @@
+# Copyright 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 <http://www.gnu.org/licenses/>.
+
+# Test continue from call instructions with shadow stack and displaced
+# stepping being enabled.
+
+require allow_ssp_tests support_displaced_stepping
+
+standard_testfile amd64-shadow-stack.c
+
+save_vars { ::env(GLIBC_TUNABLES) } {
+
+ append_environment GLIBC_TUNABLES "glibc.cpu.hwcaps" "SHSTK"
+
+ if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \
+ additional_flags="-fcf-protection=return"] } {
+ return
+ }
+
+ # Enable displaced stepping.
+ gdb_test_no_output "set displaced-stepping on"
+ gdb_test "show displaced-stepping" ".* displaced stepping .* is on.*"
+
+ if { ![runto_main] } {
+ return
+ }
+
+ # Get the address of the call to the call1 function.
+ set call1_addr -1
+ gdb_test_multiple "disassemble main" "" {
+ -re -wrap "($hex) <\\+($decimal)>:\\s*call\\s*0x.*<call1>.*" {
+ set call1_addr $expect_out(1,string)
+ pass $gdb_test_name
+ }
+ }
+
+ if { $call1_addr == -1 } {
+ return
+ }
+
+ # Get the address of the call to the call2 function.
+ set call2_addr -1
+ gdb_test_multiple "disassemble call1" "" {
+ -re -wrap "($hex) <\\+($decimal)>:\\s*call\\s*0x.*<call2>.*" {
+ set call2_addr $expect_out(1,string)
+ pass $gdb_test_name
+ }
+ }
+
+ if { $call2_addr == -1 } {
+ return
+ }
+
+ gdb_test "break *$call1_addr" \
+ "Breakpoint $decimal at $hex.*" \
+ "break at the address of the call1 instruction"
+
+ gdb_test "break *$call2_addr" \
+ "Breakpoint $decimal at $hex.*" \
+ "break at the address of the call2 instruction"
+
+ gdb_test "continue" \
+ "Breakpoint $decimal, $call1_addr in main ().*" \
+ "continue until call1 instruction"
+
+ # Test continue from breakpoint at call1 and call2 instructions.
+ gdb_test "continue" \
+ "Breakpoint $decimal, $call2_addr in call1 ().*" \
+ "continue from call1 instruction"
+
+ gdb_continue_to_end "continue from call2 instruction"
+}
diff --git a/gdb/testsuite/gdb.arch/amd64-shadow-stack.c b/gdb/testsuite/gdb.arch/amd64-shadow-stack.c
new file mode 100644
index 0000000..4a1ca1e
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-shadow-stack.c
@@ -0,0 +1,40 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ 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 <http://www.gnu.org/licenses/>. */
+
+static int
+call2 ()
+{
+ return 42; /* break call2. */
+}
+
+static int
+call1 ()
+{
+ return call2 (); /* break call1. */
+}
+
+int
+main ()
+{
+ /* Depending on instruction generation we might end up in the call
+ instruction of call1 function after "runto_main". Avoid this by
+ adding a nop instruction, to simplify the testing in
+ amd64-shadow-stack-disp-step.exp. */
+ asm ("nop");
+ call1 (); /* break main. */
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/amd64-shadow-stack.exp b/gdb/testsuite/gdb.arch/amd64-shadow-stack.exp
new file mode 100644
index 0000000..a72334a
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-shadow-stack.exp
@@ -0,0 +1,71 @@
+# 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 <http://www.gnu.org/licenses/>.
+
+# Test accessing the shadow stack pointer register.
+
+require allow_ssp_tests
+
+standard_testfile
+
+# Write PL3_SSP register with invalid shadow stack pointer value.
+proc write_invalid_ssp {} {
+ gdb_test "print /x \$pl3_ssp = 0x12345678" "= 0x12345678" "set pl3_ssp value"
+ gdb_test "print /x \$pl3_ssp" "= 0x12345678" "read pl3_ssp value after setting"
+}
+
+save_vars { ::env(GLIBC_TUNABLES) } {
+
+ append_environment GLIBC_TUNABLES "glibc.cpu.hwcaps" "SHSTK"
+
+ if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \
+ additional_flags="-fcf-protection=return"] } {
+ return
+ }
+
+ if {![runto_main]} {
+ return
+ }
+
+ with_test_prefix "invalid ssp" {
+ write_invalid_ssp
+
+ # Continue until SIGSEV to test that the value is written back to HW.
+ gdb_test "continue" \
+ [multi_line \
+ "Continuing\\." \
+ "" \
+ "Program received signal SIGSEGV, Segmentation fault\\." \
+ "$hex in main \\(\\)"] \
+ "continue to SIGSEGV"
+ }
+
+ clean_restart ${binfile}
+ if { ![runto_main] } {
+ return
+ }
+
+ with_test_prefix "restore original ssp" {
+ # Read PL3_SSP register.
+ set ssp_main [get_hexadecimal_valueof "\$pl3_ssp" "read pl3_ssp value"]
+
+ write_invalid_ssp
+
+ # Restore original value.
+ gdb_test "print /x \$pl3_ssp = $ssp_main" "= $ssp_main" "restore original value"
+
+ # Now we should not see a SIGSEV, since the original value is restored.
+ gdb_continue_to_end
+ }
+}
diff --git a/gdb/testsuite/gdb.arch/amd64-watchpoint-downgrade.exp b/gdb/testsuite/gdb.arch/amd64-watchpoint-downgrade.exp
index dcee040..5663b0d 100644
--- a/gdb/testsuite/gdb.arch/amd64-watchpoint-downgrade.exp
+++ b/gdb/testsuite/gdb.arch/amd64-watchpoint-downgrade.exp
@@ -58,7 +58,7 @@ gdb_test "starti" \
[multi_line \
"warning: watchpoint $num downgraded to software watchpoint" \
"" \
- "Program stopped\\." \
+ "(Program|Thread \[^\r\n\]) stopped\\." \
".*"]
# Watchpoint should now have downgraded to a s/w watchpoint.
diff --git a/gdb/testsuite/gdb.arch/i386-disp-step-self-call-alarm.c b/gdb/testsuite/gdb.arch/i386-disp-step-self-call-alarm.c
index 03b868c..0fb2904 100644
--- a/gdb/testsuite/gdb.arch/i386-disp-step-self-call-alarm.c
+++ b/gdb/testsuite/gdb.arch/i386-disp-step-self-call-alarm.c
@@ -16,9 +16,27 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <unistd.h>
+#include <stdlib.h>
+
+extern void test_call (void);
+
+void
+unreachable (void)
+{
+ abort ();
+}
void
setup_alarm (void)
{
alarm (300);
}
+
+int
+main ()
+{
+ setup_alarm ();
+ test_call ();
+ unreachable ();
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.arch/i386-disp-step-self-call.S b/gdb/testsuite/gdb.arch/i386-disp-step-self-call.S
index 466e50c..20a8eb7 100644
--- a/gdb/testsuite/gdb.arch/i386-disp-step-self-call.S
+++ b/gdb/testsuite/gdb.arch/i386-disp-step-self-call.S
@@ -18,33 +18,12 @@
handling. */
.text
-
- .global main
-main:
- nop
-
- call setup_alarm
-
- nop
-
-/***********************************************/
-
-/* test call/ret */
-
.global test_call
test_call:
call test_call
- nop
+ call unreachable
.global test_ret_end
test_ret_end:
nop
-/***********************************************/
-
-/* all done */
-
-done:
- pushl $0
- call exit
- hlt
.section .note.GNU-stack,"",@progbits
diff --git a/gdb/testsuite/gdb.arch/i386-prologue-skip-cf-protection-stackalign.c b/gdb/testsuite/gdb.arch/i386-prologue-skip-cf-protection-stackalign.c
new file mode 100644
index 0000000..f55cee5
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/i386-prologue-skip-cf-protection-stackalign.c
@@ -0,0 +1,27 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 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 <http://www.gnu.org/licenses/>. */
+
+#include <alloca.h>
+
+int
+main (int argc, char **argv)
+{
+ volatile __attribute__ ((__aligned__ (64))) int a;
+ volatile char *p = (char *) alloca (argc * 12);
+ p[2] = 'b';
+ return 1;
+}
diff --git a/gdb/testsuite/gdb.arch/i386-prologue-skip-cf-protection.exp b/gdb/testsuite/gdb.arch/i386-prologue-skip-cf-protection.exp
index eb93127..06285ce 100644
--- a/gdb/testsuite/gdb.arch/i386-prologue-skip-cf-protection.exp
+++ b/gdb/testsuite/gdb.arch/i386-prologue-skip-cf-protection.exp
@@ -19,41 +19,65 @@
# This option places an `endbr32`/`endbr64` instruction at the start of
# all functions, which can interfere with prologue analysis.
-standard_testfile .c
-set binfile ${binfile}
+standard_testfile .c -stackalign.c
require {is_any_target x86_64-*-* i?86-*-*}
-
require supports_fcf_protection
-set opts {debug additional_flags=-fcf-protection=full}
+# Tests if breakpoint set on main is placed past main's entry.
+proc test_run {} {
+ # Get start address of function main.
+ set main_addr [get_integer_valueof &main -1]
+ gdb_assert {$main_addr != -1}
-if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable $opts] != "" } {
- untested "failed to compile"
- return
-}
+ set bp_addr -1
-clean_restart ${binfile}
+ # Put breakpoint on main, get the address where the breakpoint was installed.
+ gdb_test_multiple "break -q main" "break on main, get address" {
+ -re -wrap "Breakpoint $::decimal at ($::hex).*" {
+ set bp_addr $expect_out(1,string)
-# Get start address of function main.
-set main_addr [get_integer_valueof &main -1]
-gdb_assert {$main_addr != -1}
+ # Convert to decimal.
+ set bp_addr [expr $bp_addr]
-set bp_addr -1
+ pass $gdb_test_name
+ }
+ }
-# Put breakpoint on main, get the address where the breakpoint was installed.
-gdb_test_multiple "break -q main" "break on main, get address" {
- -re -wrap "Breakpoint $decimal at ($hex).*" {
- set bp_addr $expect_out(1,string)
+ # Make sure some prologue was skipped.
+ gdb_assert {$bp_addr != -1 && $bp_addr > $main_addr} \
+ "breakpoint placed past main's entry"
+}
- # Convert to decimal.
- set bp_addr [expr $bp_addr]
+with_test_prefix "skip-cf-protection" {
+ set opts {debug additional_flags=-fcf-protection=full}
- pass $gdb_test_name
+ if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable \
+ $opts] != "" } {
+ untested "failed to compile"
+ return
}
+
+ clean_restart ${binfile}
+
+ test_run
}
-if { $bp_addr != -1 } {
- # Make sure some prologue was skipped.
- gdb_assert {$bp_addr > $main_addr}
+# Now, make sure that the prologue analysis does not end up at function's entry
+# when stack alignment sequence is generated right after 'endbr64'/'endbr32'.
+# That could happen if GDB handled those incorrectly - there was a bug that
+# checked for those two in incorrect order, which caused such issue.
+with_test_prefix "skip-cf-protection-stackalign" {
+ # gcc is easier to make it produce the sequence of interest.
+ if { ![is_c_compiler_gcc] } {
+ unsupported "stackalign test part requires gcc compiler"
+ return
+ }
+
+ if { [prepare_for_testing "failed to prepare" "${testfile}-stackalign" \
+ $srcfile2 [list optimize=-O0 additional_flags=-fcf-protection=full]] } {
+ return
+ }
+
+ test_run
}