From 03eedad2ad2e292cf16243c93d685c3c9cacd81e Mon Sep 17 00:00:00 2001 From: James McGregor Date: Fri, 16 Aug 2024 10:23:46 +0100 Subject: [PATCH] arm-gcs: add recipe for GDB with GCS support The GCS support patches are based on GDB 15. Copy the GDB 14.2 recipe from meta, upgrade to 15.1, and add the patches. Signed-off-by: James McGregor --- .../recipes-devtools/gdb/files/gcs.patch | 3667 +++++++++++++++++ meta-arm-gcs/recipes-devtools/gdb/gdb_15.1.bb | 40 + .../recipes-devtools/gdb/gdb_15.1.bbappend | 3 + 3 files changed, 3710 insertions(+) create mode 100644 meta-arm-gcs/recipes-devtools/gdb/files/gcs.patch create mode 100644 meta-arm-gcs/recipes-devtools/gdb/gdb_15.1.bb create mode 100644 meta-arm-gcs/recipes-devtools/gdb/gdb_15.1.bbappend diff --git a/meta-arm-gcs/recipes-devtools/gdb/files/gcs.patch b/meta-arm-gcs/recipes-devtools/gdb/files/gcs.patch new file mode 100644 index 00000000..698d7c50 --- /dev/null +++ b/meta-arm-gcs/recipes-devtools/gdb/files/gcs.patch @@ -0,0 +1,3667 @@ +Upstream-Status: Pending [https://git.linaro.org/people/thiago.bauermann/binutils-gdb.git/?h=guarded-control-stack] +Signed-off-by: James McGregor + +From 9554f581f907a0514d566506529d2a416c62144a Mon Sep 17 00:00:00 2001 +From: Thiago Jung Bauermann +Date: Wed, 20 Dec 2023 15:15:45 -0300 +Subject: [PATCH 01/27] gdb/testsuite: Add gdb.arch/aarch64-gcs.exp testcase + +Also add allow_aarch64_gcs_tests procedure to determine whether Guarded Control Stack +tests should run. +--- + gdb/testsuite/gdb.arch/aarch64-gcs.c | 22 +++++++ + gdb/testsuite/gdb.arch/aarch64-gcs.exp | 30 +++++++++ + gdb/testsuite/lib/gdb.exp | 88 ++++++++++++++++++++++++++ + 3 files changed, 140 insertions(+) + create mode 100644 gdb/testsuite/gdb.arch/aarch64-gcs.c + create mode 100644 gdb/testsuite/gdb.arch/aarch64-gcs.exp + +diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs.c b/gdb/testsuite/gdb.arch/aarch64-gcs.c +new file mode 100644 +index 00000000000..a450ad0dab6 +--- /dev/null ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs.c +@@ -0,0 +1,22 @@ ++/* This test program is part of GDB, the GNU debugger. ++ ++ Copyright 2023 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 . */ ++ ++int ++main (void) ++{ ++ return 0; ++} +diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs.exp b/gdb/testsuite/gdb.arch/aarch64-gcs.exp +new file mode 100644 +index 00000000000..1abf0e2440e +--- /dev/null ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs.exp +@@ -0,0 +1,30 @@ ++# Copyright 2023 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 . ++ ++# 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 -1 ++} ++ ++if ![runto_main] { ++ return -1 ++} ++ ++gdb_test "print \$gcspr" ". = $hex" "GDB knows about GCSPR" +diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp +index dfe19c9410d..b5d35e6a4dc 100644 +--- a/gdb/testsuite/lib/gdb.exp ++++ b/gdb/testsuite/lib/gdb.exp +@@ -4618,6 +4618,94 @@ gdb_caching_proc allow_aarch64_mops_tests {} { + return $allow_mops_tests + } + ++# Run a test on the target to see if it supports Aarch64 GCS extensions. ++# Return 0 if so, 1 if it does not. Note this causes a restart of GDB. ++ ++gdb_caching_proc allow_aarch64_gcs_tests {} { ++ global srcdir subdir gdb_prompt inferior_exited_re ++ ++ set me "allow_aarch64_gcs_tests" ++ ++ if { ![is_aarch64_target]} { ++ return 0 ++ } ++ ++ # In binutils > 2.41, ARMv8-A contains the CHK extension. ++ set compile_flags "{additional_flags=-march=armv8-a}" ++ ++ # Compile a program that tests the GCS feature. ++ set src { ++ #include ++ ++ int main() { ++ bool gcs_supported; ++ register long features __asm__ ("x16") = 1; ++ ++ asm ("chkfeat %0" ++ : "+r" (features) ++ : "r" (features)); ++ ++ /* If GCS is supported, chkfeat clears bit 0 of x16. */ ++ gcs_supported = features != 1; ++ ++ /* Return success if GCS is supported. */ ++ return !gcs_supported; ++ } ++ } ++ if {![gdb_simple_compile $me $src executable $compile_flags]} { ++ # Try again, but with a raw hex instruction so we don't rely on ++ # assembler support for GCS. ++ ++ # Compile a program that tests the GCS feature. ++ set src { ++ #include ++ ++ int main() { ++ bool gcs_supported; ++ register long features __asm__ ("x16") = 1; ++ ++ /* chkfeat x16. */ ++ asm (".word 0xD503251F" ++ : "+r" (features) ++ : "r" (features)); ++ ++ /* If GCS is supported, chkfeat clears bit 0 of x16. */ ++ gcs_supported = features != 1; ++ ++ /* Return success if GCS is supported. */ ++ return !gcs_supported; ++ } ++ } ++ ++ if {![gdb_simple_compile $me $src executable $compile_flags]} { ++ return 0 ++ } ++ } ++ ++ # Compilation succeeded so now run it via gdb. ++ clean_restart $obj ++ gdb_run_cmd ++ gdb_expect { ++ -re ".*$inferior_exited_re with code 01.*${gdb_prompt} $" { ++ verbose -log "\n$me gcs support not detected" ++ set allow_gcs_tests 0 ++ } ++ -re ".*$inferior_exited_re normally.*${gdb_prompt} $" { ++ verbose -log "\n$me: gcs support detected" ++ set allow_gcs_tests 1 ++ } ++ default { ++ warning "\n$me: default case taken" ++ set allow_gcs_tests 0 ++ } ++ } ++ gdb_exit ++ remote_file build delete $obj ++ ++ verbose "$me: returning $allow_gcs_tests" 2 ++ return $allow_gcs_tests ++} ++ + # A helper that compiles a test case to see if __int128 is supported. + proc gdb_int128_helper {lang} { + return [gdb_can_simple_compile "i128-for-$lang" { +-- +2.25.1 + + +From 5aba29f1ec566bbf2a29f49671963dd3e71fb278 Mon Sep 17 00:00:00 2001 +From: Thiago Jung Bauermann +Date: Tue, 24 Oct 2023 15:07:53 -0300 +Subject: [PATCH 02/27] Add AArch64 GCS feature. + +--- + gdb/aarch64-tdep.c | 4 ++++ + gdb/arch/aarch64.c | 5 +++++ + gdb/arch/aarch64.h | 3 +++ + gdb/features/Makefile | 1 + + gdb/features/aarch64-gcs.c | 14 ++++++++++++++ + gdb/features/aarch64-gcs.xml | 11 +++++++++++ + 6 files changed, 38 insertions(+) + create mode 100644 gdb/features/aarch64-gcs.c + create mode 100644 gdb/features/aarch64-gcs.xml + +diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c +index e4bca6c6632..d157aea8f21 100644 +--- a/gdb/aarch64-tdep.c ++++ b/gdb/aarch64-tdep.c +@@ -4045,6 +4045,10 @@ aarch64_features_from_target_desc (const struct target_desc *tdesc) + features.sme2 = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.sme2") + != nullptr); + ++ /* Check for the GCS feature. */ ++ features.gcs = (tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.gcs") ++ != nullptr); ++ + return features; + } + +diff --git a/gdb/arch/aarch64.c b/gdb/arch/aarch64.c +index 5526aa1b580..b4f4e6892ad 100644 +--- a/gdb/arch/aarch64.c ++++ b/gdb/arch/aarch64.c +@@ -26,6 +26,7 @@ + #include "../features/aarch64-sme.c" + #include "../features/aarch64-sme2.c" + #include "../features/aarch64-tls.c" ++#include "../features/aarch64-gcs.c" + + /* See arch/aarch64.h. */ + +@@ -65,6 +66,10 @@ aarch64_create_target_description (const aarch64_features &features) + if (features.sme2) + regnum = create_feature_aarch64_sme2 (tdesc.get (), regnum); + ++ /* FIXME: Think about whether the regnum for GCS should be fixed. */ ++ if (features.gcs) ++ regnum = create_feature_aarch64_gcs (tdesc.get (), regnum); ++ + return tdesc.release (); + } + +diff --git a/gdb/arch/aarch64.h b/gdb/arch/aarch64.h +index b4c0111aeb4..36f25ea17e2 100644 +--- a/gdb/arch/aarch64.h ++++ b/gdb/arch/aarch64.h +@@ -51,6 +51,9 @@ struct aarch64_features + + /* Whether SME2 is supported. */ + bool sme2 = false; ++ ++ /* Whether Guarded Control Stack is supported. */ ++ bool gcs = false; + }; + + inline bool operator==(const aarch64_features &lhs, const aarch64_features &rhs) +diff --git a/gdb/features/Makefile b/gdb/features/Makefile +index ddf4ec295a9..afc81499021 100644 +--- a/gdb/features/Makefile ++++ b/gdb/features/Makefile +@@ -202,6 +202,7 @@ FEATURE_XMLFILES = aarch64-core.xml \ + aarch64-fpu.xml \ + aarch64-pauth.xml \ + aarch64-mte.xml \ ++ aarch64-gcs.xml \ + arc/v1-core.xml \ + arc/v1-aux.xml \ + arc/v2-core.xml \ +diff --git a/gdb/features/aarch64-gcs.c b/gdb/features/aarch64-gcs.c +new file mode 100644 +index 00000000000..2b2caf29cc8 +--- /dev/null ++++ b/gdb/features/aarch64-gcs.c +@@ -0,0 +1,14 @@ ++/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro: ++ Original: aarch64-gcs.xml */ ++ ++#include "gdbsupport/tdesc.h" ++ ++static int ++create_feature_aarch64_gcs (struct target_desc *result, long regnum) ++{ ++ struct tdesc_feature *feature; ++ ++ feature = tdesc_create_feature (result, "org.gnu.gdb.aarch64.gcs"); ++ tdesc_create_reg (feature, "gcspr", regnum++, 1, "system", 64, "data_ptr"); ++ return regnum; ++} +diff --git a/gdb/features/aarch64-gcs.xml b/gdb/features/aarch64-gcs.xml +new file mode 100644 +index 00000000000..fd00ce06b30 +--- /dev/null ++++ b/gdb/features/aarch64-gcs.xml +@@ -0,0 +1,11 @@ ++ ++ ++ ++ ++ ++ ++ +-- +2.25.1 + + +From 52e50090910a0ebca00b9c92d6fdf80a16a80d6e Mon Sep 17 00:00:00 2001 +From: Thiago Jung Bauermann +Date: Thu, 21 Dec 2023 12:17:12 -0300 +Subject: [PATCH 03/27] gdb/aarch64-linux: Initial Guarded Control Stack + support + +This commit adds the GCSPR register. +--- + gdb/aarch64-linux-nat.c | 72 ++++++++++++++++++++++++++ + gdb/aarch64-linux-tdep.c | 21 ++++++++ + gdb/aarch64-tdep.c | 27 ++++++++++ + gdb/aarch64-tdep.h | 10 ++++ + gdb/arch/aarch64-gcs-linux.h | 42 +++++++++++++++ + gdb/arch/aarch64.h | 3 +- + gdb/testsuite/gdb.arch/aarch64-gcs.exp | 2 +- + gdbserver/linux-aarch64-low.cc | 5 ++ + include/elf/common.h | 3 ++ + 9 files changed, 183 insertions(+), 2 deletions(-) + create mode 100644 gdb/arch/aarch64-gcs-linux.h + +diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c +index 2e6541f53c3..b3d2091f413 100644 +--- a/gdb/aarch64-linux-nat.c ++++ b/gdb/aarch64-linux-nat.c +@@ -51,6 +51,7 @@ + #include "gdb_proc_service.h" + #include "arch-utils.h" + ++#include "arch/aarch64-gcs-linux.h" + #include "arch/aarch64-mte-linux.h" + + #include "nat/aarch64-mte-linux-ptrace.h" +@@ -544,6 +545,64 @@ store_tlsregs_to_thread (struct regcache *regcache) + perror_with_name (_("unable to store TLS register")); + } + ++/* Fill GDB's register array with the GCS register values from ++ the current thread. */ ++ ++static void ++fetch_gcsregs_from_thread (struct regcache *regcache) ++{ ++ aarch64_gdbarch_tdep *tdep ++ = gdbarch_tdep (regcache->arch ()); ++ int regno = tdep->gcs_reg_base; ++ ++ gdb_assert (regno != -1); ++ ++ struct user_gcs user_gcs; ++ struct iovec iovec; ++ ++ iovec.iov_base = &user_gcs; ++ iovec.iov_len = sizeof (user_gcs); ++ ++ int tid = get_ptrace_pid (regcache->ptid ()); ++ if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_GCS, &iovec) != 0) ++ perror_with_name (_("unable to fetch GCS registers")); ++ ++ regcache->raw_supply (regno, &user_gcs.gcspr_el0); ++} ++ ++/* Store to the current thread the valid GCS register set in the GDB's ++ register array. */ ++ ++static void ++store_gcsregs_to_thread (struct regcache *regcache) ++{ ++ aarch64_gdbarch_tdep *tdep ++ = gdbarch_tdep (regcache->arch ()); ++ int regno = tdep->gcs_reg_base; ++ ++ gdb_assert (regno != -1); ++ ++ if (REG_VALID != regcache->get_register_status (regno)) ++ return; ++ ++ struct user_gcs user_gcs; ++ struct iovec iovec; ++ ++ iovec.iov_base = &user_gcs; ++ iovec.iov_len = sizeof (user_gcs); ++ ++ int tid = get_ptrace_pid (regcache->ptid ()); ++ if (ptrace (PTRACE_GETREGSET, tid, NT_ARM_GCS, &iovec) != 0) ++ perror_with_name (_ ("unable to fetch GCS registers")); ++ ++ uint64_t gcspr; ++ regcache->raw_collect (regno, &gcspr); ++ user_gcs.gcspr_el0 = gcspr; ++ ++ if (ptrace (PTRACE_SETREGSET, tid, NT_ARM_GCS, &iovec) != 0) ++ perror_with_name (_("unable to store GCS registers")); ++} ++ + /* The AArch64 version of the "fetch_registers" target_ops method. Fetch + REGNO from the target and place the result into REGCACHE. */ + +@@ -579,6 +638,9 @@ aarch64_fetch_registers (struct regcache *regcache, int regno) + + if (tdep->has_sme2 ()) + fetch_zt_from_thread (regcache); ++ ++ if (tdep->has_gcs ()) ++ fetch_gcsregs_from_thread (regcache); + } + /* General purpose register? */ + else if (regno < AARCH64_V0_REGNUM) +@@ -611,6 +673,9 @@ aarch64_fetch_registers (struct regcache *regcache, int regno) + && regno >= tdep->tls_regnum_base + && regno < tdep->tls_regnum_base + tdep->tls_register_count) + fetch_tlsregs_from_thread (regcache); ++ /* GCS register? */ ++ else if (tdep->has_gcs () && (regno == tdep->gcs_reg_base)) ++ fetch_gcsregs_from_thread (regcache); + } + + /* A version of the "fetch_registers" target_ops method used when running +@@ -682,6 +747,9 @@ aarch64_store_registers (struct regcache *regcache, int regno) + + if (tdep->has_sme2 ()) + store_zt_to_thread (regcache); ++ ++ if (tdep->has_gcs ()) ++ store_gcsregs_to_thread (regcache); + } + /* General purpose register? */ + else if (regno < AARCH64_V0_REGNUM) +@@ -708,6 +776,9 @@ aarch64_store_registers (struct regcache *regcache, int regno) + && regno >= tdep->tls_regnum_base + && regno < tdep->tls_regnum_base + tdep->tls_register_count) + store_tlsregs_to_thread (regcache); ++ /* GCS register? */ ++ else if (tdep->has_gcs () && (regno == tdep->gcs_reg_base)) ++ store_gcsregs_to_thread (regcache); + + /* PAuth registers are read-only. */ + } +@@ -887,6 +958,7 @@ aarch64_linux_nat_target::read_description () + features.tls = aarch64_tls_register_count (tid); + /* SME feature check. */ + features.svq = aarch64_za_get_svq (tid); ++ features.gcs = hwcap2 & HWCAP2_GCS; + + /* Check for SME2 support. */ + if ((hwcap2 & HWCAP2_SME2) || (hwcap2 & HWCAP2_SME2P1)) +diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c +index a1296a8f0c7..d4e948d3b37 100644 +--- a/gdb/aarch64-linux-tdep.c ++++ b/gdb/aarch64-linux-tdep.c +@@ -48,6 +48,7 @@ + #include "record-full.h" + #include "linux-record.h" + ++#include "arch/aarch64-gcs-linux.h" + #include "arch/aarch64-mte-linux.h" + #include "arch/aarch64-scalable-linux.h" + +@@ -1605,6 +1606,25 @@ aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch, + cb (".reg-aarch-tls", sizeof_tls_regset, sizeof_tls_regset, + &aarch64_linux_tls_regset, "TLS register", cb_data); + } ++ ++ /* Handle GCS registers. */ ++ if (tdep->has_gcs ()) ++ { ++ /* Create this on the fly in order to handle the variable location. */ ++ const struct regcache_map_entry gcs_regmap[] = ++ { ++ { 1, tdep->gcs_reg_base, 8 }, ++ { 0 } ++ }; ++ ++ const struct regset aarch64_linux_gcs_regset = ++ { ++ gcs_regmap, regcache_supply_regset, regcache_collect_regset ++ }; ++ ++ cb (".reg-aarch-gcs", sizeof (struct user_gcs), sizeof (struct user_gcs), ++ &aarch64_linux_gcs_regset, "GCS registers", cb_data); ++ } + } + + /* Implement the "core_read_description" gdbarch method. */ +@@ -1630,6 +1650,7 @@ aarch64_linux_core_read_description (struct gdbarch *gdbarch, + features.vq = aarch64_linux_core_read_vq_from_sections (gdbarch, abfd); + features.pauth = hwcap & AARCH64_HWCAP_PACA; + features.mte = hwcap2 & HWCAP2_MTE; ++ features.gcs = hwcap2 & HWCAP2_GCS; + + /* Handle the TLS section. */ + asection *tls = bfd_get_section_by_name (abfd, ".reg-aarch-tls"); +diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c +index d157aea8f21..0d32b948924 100644 +--- a/gdb/aarch64-tdep.c ++++ b/gdb/aarch64-tdep.c +@@ -158,6 +158,12 @@ static const char *const aarch64_mte_register_names[] = + "tag_ctl" + }; + ++static const char *const aarch64_gcs_register_names[] = { ++ /* Guarded Control Stack Pointer Register. */ ++ /* FIXME: Change to gcspr_el0? */ ++ "gcspr" ++}; ++ + static int aarch64_stack_frame_destroyed_p (struct gdbarch *, CORE_ADDR); + + /* AArch64 prologue cache structure. */ +@@ -4444,6 +4450,23 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) + int first_w_regnum = num_pseudo_regs; + num_pseudo_regs += 31; + ++ const struct tdesc_feature *feature_gcs ++ = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.gcs"); ++ int first_gcs_regnum = -1; ++ /* Add the GCS registers. */ ++ if (feature_gcs != NULL) ++ { ++ first_gcs_regnum = num_regs; ++ /* Validate the descriptor provides the mandatory GCS registers and ++ allocate their numbers. */ ++ for (i = 0; i < ARRAY_SIZE (aarch64_gcs_register_names); i++) ++ valid_p &= tdesc_numbered_register (feature_gcs, tdesc_data.get (), ++ first_gcs_regnum + i, ++ aarch64_gcs_register_names[i]); ++ ++ num_regs += i; ++ } ++ + if (!valid_p) + return nullptr; + +@@ -4465,6 +4488,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) + tdep->mte_reg_base = first_mte_regnum; + tdep->tls_regnum_base = first_tls_regnum; + tdep->tls_register_count = tls_register_count; ++ tdep->gcs_reg_base = first_gcs_regnum; + + /* Set the SME register set details. The pseudo-registers will be adjusted + later. */ +@@ -4736,6 +4760,9 @@ aarch64_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file) + pulongest (tdep->sme_tile_pseudo_base)); + gdb_printf (file, _("aarch64_dump_tdep: sme_svq = %s\n"), + pulongest (tdep->sme_svq)); ++ ++ gdb_printf (file, _ ("aarch64_dump_tdep: gcs_reg_base = %d\n"), ++ tdep->gcs_reg_base); + } + + #if GDB_SELF_TEST +diff --git a/gdb/aarch64-tdep.h b/gdb/aarch64-tdep.h +index 0e6024bfcbc..9508b5fb302 100644 +--- a/gdb/aarch64-tdep.h ++++ b/gdb/aarch64-tdep.h +@@ -182,6 +182,16 @@ struct aarch64_gdbarch_tdep : gdbarch_tdep_base + { + return sme2_zt0_regnum > 0; + } ++ ++ /* First GCS register. This is -1 if no GCS registers are available. */ ++ int gcs_reg_base = -1; ++ ++ /* Returns true if the target supports GCS. */ ++ bool ++ has_gcs () const ++ { ++ return gcs_reg_base != -1; ++ } + }; + + const target_desc *aarch64_read_description (const aarch64_features &features); +diff --git a/gdb/arch/aarch64-gcs-linux.h b/gdb/arch/aarch64-gcs-linux.h +new file mode 100644 +index 00000000000..8da12325c79 +--- /dev/null ++++ b/gdb/arch/aarch64-gcs-linux.h +@@ -0,0 +1,42 @@ ++/* Common Linux target-dependent definitions for AArch64 GCS ++ ++ Copyright (C) 2023 Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ 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 . */ ++ ++#ifndef ARCH_AARCH64_GCS_LINUX_H ++#define ARCH_AARCH64_GCS_LINUX_H ++ ++#include ++ ++/* Feature check for Guarded Control Stack. */ ++#ifndef HWCAP2_GCS ++#define HWCAP2_GCS (1UL << 48) ++#endif ++ ++/* The GCS regset consists of a single 64-bit register. */ ++#define AARCH64_LINUX_SIZEOF_GCS 8 ++ ++/* GCS state (NT_ARM_GCS). */ ++ ++struct user_gcs ++{ ++ uint64_t features_enabled; ++ uint64_t features_locked; ++ uint64_t gcspr_el0; ++}; ++ ++#endif /* ARCH_AARCH64_GCS_LINUX_H */ +diff --git a/gdb/arch/aarch64.h b/gdb/arch/aarch64.h +index 36f25ea17e2..b3d2c78f236 100644 +--- a/gdb/arch/aarch64.h ++++ b/gdb/arch/aarch64.h +@@ -63,7 +63,8 @@ inline bool operator==(const aarch64_features &lhs, const aarch64_features &rhs) + && lhs.mte == rhs.mte + && lhs.tls == rhs.tls + && lhs.svq == rhs.svq +- && lhs.sme2 == rhs.sme2; ++ && lhs.sme2 == rhs.sme2 ++ && lhs.gcs == rhs.gcs; + } + + namespace std +diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs.exp b/gdb/testsuite/gdb.arch/aarch64-gcs.exp +index 1abf0e2440e..f3a2c2b6aa0 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs.exp ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs.exp +@@ -27,4 +27,4 @@ if ![runto_main] { + return -1 + } + +-gdb_test "print \$gcspr" ". = $hex" "GDB knows about GCSPR" ++gdb_test "print \$gcspr" ". = \\(void \\*\\) $hex" "GDB knows about GCSPR" +diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc +index eb30c31f8f8..e15dde97a4d 100644 +--- a/gdbserver/linux-aarch64-low.cc ++++ b/gdbserver/linux-aarch64-low.cc +@@ -39,6 +39,7 @@ + + #include "gdb_proc_service.h" + #include "arch/aarch64.h" ++#include "arch/aarch64-gcs-linux.h" + #include "arch/aarch64-mte-linux.h" + #include "arch/aarch64-scalable-linux.h" + #include "linux-aarch32-tdesc.h" +@@ -911,6 +912,10 @@ aarch64_adjust_register_sets (const struct aarch64_features &features) + if (features.sme2) + regset->size = AARCH64_SME2_ZT0_SIZE; + break; ++ case NT_ARM_GCS: ++ if (features.gcs) ++ regset->size = AARCH64_LINUX_SIZEOF_GCS; ++ break; + default: + gdb_assert_not_reached ("Unknown register set found."); + } +diff --git a/include/elf/common.h b/include/elf/common.h +index c9920e7731a..09d11ae586b 100644 +--- a/include/elf/common.h ++++ b/include/elf/common.h +@@ -739,6 +739,9 @@ + /* Note: name must be "LINUX". */ + #define NT_ARM_ZT 0x40d /* AArch64 SME2 ZT registers. */ + /* Note: name must be "LINUX". */ ++#define NT_ARM_GCS 0x40e /* AArch64 Guarded Control Stack ++ registers. */ ++ /* Note name must be "LINUX". */ + #define NT_ARC_V2 0x600 /* ARC HS accumulator/extra registers. */ + /* note name must be "LINUX". */ + #define NT_LARCH_CPUCFG 0xa00 /* LoongArch CPU config registers */ +-- +2.25.1 + + +From 86d0ae5d87e12d886ceb1e0bed504acfa764c40e Mon Sep 17 00:00:00 2001 +From: Thiago Jung Bauermann +Date: Fri, 22 Dec 2023 15:31:03 -0300 +Subject: [PATCH 04/27] gdb/aarch64-linux: Implement GCS signal frame context. + +--- + gdb/aarch64-linux-tdep.c | 56 +++++++++++++++ + gdb/arch/aarch64-gcs-linux.h | 5 ++ + gdb/testsuite/gdb.arch/aarch64-gcs.c | 96 +++++++++++++++++++++++++- + gdb/testsuite/gdb.arch/aarch64-gcs.exp | 8 ++- + 4 files changed, 162 insertions(+), 3 deletions(-) + +diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c +index d4e948d3b37..ff08913cf09 100644 +--- a/gdb/aarch64-linux-tdep.c ++++ b/gdb/aarch64-linux-tdep.c +@@ -162,6 +162,7 @@ + #define AARCH64_ZA_MAGIC 0x54366345 + #define AARCH64_TPIDR2_MAGIC 0x54504902 + #define AARCH64_ZT_MAGIC 0x5a544e01 ++#define AARCH64_GCS_MAGIC 0x47435300 + + /* Defines for the extra_context that follows an AARCH64_EXTRA_MAGIC. */ + #define AARCH64_EXTRA_DATAP_OFFSET 8 +@@ -203,6 +204,11 @@ + the signal context state. */ + #define AARCH64_SME2_CONTEXT_REGS_OFFSET 16 + ++/* GCSPR register value offset in the GCS signal frame context. */ ++#define AARCH64_GCS_CONTEXT_GCSPR_OFFSET 8 ++/* features_enabled value offset in the GCS signal frame context. */ ++#define AARCH64_GCS_CONTEXT_FEATURES_ENABLED_OFFSET 16 ++ + /* Holds information about the signal frame. */ + struct aarch64_linux_sigframe + { +@@ -243,6 +249,13 @@ struct aarch64_linux_sigframe + bool za_payload = false; + /* True if we have a ZT entry in the signal context, false otherwise. */ + bool zt_available = false; ++ ++ /* True if we have a GCS entry in the signal context, false otherwise. */ ++ bool gcs_availabe = false; ++ /* The Guarded Control Stack Pointer Register. */ ++ uint64_t gcspr; ++ /* Flags indicating which GCS features are enabled for the thread. */ ++ uint64_t gcs_features_enabled; + }; + + /* Read an aarch64_ctx, returning the magic value, and setting *SIZE to the +@@ -523,6 +536,40 @@ aarch64_linux_read_signal_frame_info (const frame_info_ptr &this_frame, + signal_frame.zt_section = section; + signal_frame.zt_available = true; + ++ section += size; ++ break; ++ } ++ case AARCH64_GCS_MAGIC: ++ { ++ gdb_byte buf[8]; ++ ++ /* Extract the GCSPR. */ ++ if (target_read_memory (section + AARCH64_GCS_CONTEXT_GCSPR_OFFSET, ++ buf, 8) != 0) ++ { ++ warning (_("Failed to read the GCSPR from the GCS signal frame" ++ " context.")); ++ section += size; ++ break; ++ } ++ ++ signal_frame.gcspr = extract_unsigned_integer (buf, 8, byte_order); ++ ++ /* Extract the features_enabled field. */ ++ if (target_read_memory (section ++ + AARCH64_GCS_CONTEXT_FEATURES_ENABLED_OFFSET, ++ buf, 8) != 0) ++ { ++ warning (_("Failed to read the enabled features from the GCS" ++ " signal frame context.")); ++ section += size; ++ break; ++ } ++ ++ // FIXME: This field is currently unused by GDB. ++ signal_frame.gcs_features_enabled ++ = extract_unsigned_integer (buf, 8, byte_order); ++ signal_frame.gcs_availabe = true; + section += size; + break; + } +@@ -700,6 +747,15 @@ aarch64_linux_sigframe_init (const struct tramp_frame *self, + + AARCH64_TPIDR2_CONTEXT_TPIDR2_OFFSET); + } + ++ /* Restore the GCSPR register, if the target supports it and if there is ++ an entry for it. */ ++ if (signal_frame.gcs_availabe && tdep->has_gcs ()) ++ { ++ /* Restore GCSPR. */ ++ trad_frame_set_reg_value (this_cache, tdep->gcs_reg_base, ++ signal_frame.gcspr); ++ } ++ + trad_frame_set_id (this_cache, frame_id_build (signal_frame.sp, func)); + } + +diff --git a/gdb/arch/aarch64-gcs-linux.h b/gdb/arch/aarch64-gcs-linux.h +index 8da12325c79..65f70a72b15 100644 +--- a/gdb/arch/aarch64-gcs-linux.h ++++ b/gdb/arch/aarch64-gcs-linux.h +@@ -30,6 +30,9 @@ + /* The GCS regset consists of a single 64-bit register. */ + #define AARCH64_LINUX_SIZEOF_GCS 8 + ++/* Make sure we only define these if the kernel header doesn't. */ ++#ifndef GCS_MAGIC ++ + /* GCS state (NT_ARM_GCS). */ + + struct user_gcs +@@ -39,4 +42,6 @@ struct user_gcs + uint64_t gcspr_el0; + }; + ++#endif /* GCS_MAGIC */ ++ + #endif /* ARCH_AARCH64_GCS_LINUX_H */ +diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs.c b/gdb/testsuite/gdb.arch/aarch64-gcs.c +index a450ad0dab6..1364dd857a2 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs.c ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs.c +@@ -15,8 +15,102 @@ + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + ++#include ++#include ++#include ++#include ++#include ++ ++/* Feature check for Guarded Control Stack. */ ++#ifndef HWCAP2_GCS ++#define HWCAP2_GCS (1UL << 48) ++#endif ++ ++#ifndef PR_GET_SHADOW_STACK_STATUS ++#define PR_GET_SHADOW_STACK_STATUS 71 ++#define PR_SET_SHADOW_STACK_STATUS 72 ++#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; \ ++ \ ++ asm volatile("mrs %0, S3_3_C2_C5_1" : "=r"(gcspr) : : "cc"); \ ++ \ ++ gcspr; \ ++ }) ++ ++static void __attribute__ ((noinline)) ++function1 (int arg) ++{ ++ printf ("Called function1 with argument %d\n", arg); ++} ++ + int + main (void) + { +- return 0; ++ unsigned long gcs_mode, *gcspr; ++ int ret; ++ ++ if (!(getauxval (AT_HWCAP2) & HWCAP2_GCS)) ++ 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. ++ */ ++ 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; ++ } ++ } ++ ++ function1 (1); /* break here */ ++ ++ gcspr = get_gcspr (); ++ ++ /* Cause a SEGV. */ ++ *gcspr = 1; ++ ++ /* 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 +index f3a2c2b6aa0..c207c62be8f 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs.exp ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs.exp +@@ -23,8 +23,12 @@ if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } { + return -1 + } + +-if ![runto_main] { +- return -1 ++set linespec ${srcfile}:[gdb_get_line_number "break here"] ++ ++if ![runto ${linespec}] { ++ return + } + + gdb_test "print \$gcspr" ". = \\(void \\*\\) $hex" "GDB knows about GCSPR" ++ ++gdb_test "next" "signal \\(SIGSEGV.*" "next to signal" +-- +2.25.1 + + +From 1278edbd8a220db7e631f1e5110c74f8d1f60a5c Mon Sep 17 00:00:00 2001 +From: Thiago Jung Bauermann +Date: Wed, 27 Dec 2023 23:13:30 -0300 +Subject: [PATCH 05/27] gdb.arch/aarch64-gcs.exp: Fix provoking of SEGV + +Also, improve check of $gcspr by comparing with inferior's gcspr. + +The SEGV doesn't have the expected si_code = 10 (SEGV_CPERR: Control +protection fault) though: + + continue + Continuing. + gcspr = 0xfffff7e0fff8 + + Program received signal SIGSEGV, Segmentation fault. + 0x0000aaaaaaaa0a54 in main () at /home/bauermann/src/binutils-gdb/gdb/testsuite/gdb.arch/aarch64-gcs.c:114 + 114 *stack = 1; + (gdb) PASS: gdb.arch/aarch64-gcs.exp: continue to SEGV + print $_siginfo.si_code + $3 = 2 + (gdb) FAIL: gdb.arch/aarch64-gcs.exp: Test value of si_code when GCS SIGSEGV happens + testcase /home/bauermann/src/binutils-gdb/gdb/testsuite/gdb.arch/aarch64-gcs.exp completed in 160 seconds + +Note: si_code = 2 is SEGV_ACCERR: invalid permissions for mapped object. +--- + gdb/testsuite/gdb.arch/aarch64-gcs.c | 56 +++++++++++++------------- + gdb/testsuite/gdb.arch/aarch64-gcs.exp | 7 +++- + 2 files changed, 35 insertions(+), 28 deletions(-) + +diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs.c b/gdb/testsuite/gdb.arch/aarch64-gcs.c +index 1364dd857a2..9c3b67619ad 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs.c ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs.c +@@ -18,7 +18,9 @@ + #include + #include + #include ++#include + #include ++#include + #include + + /* Feature check for Guarded Control Stack. */ +@@ -32,11 +34,13 @@ + #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. +- */ ++#ifndef __NR_map_shadow_stack ++#define __NR_map_shadow_stack 453 ++#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); \ +@@ -63,30 +67,20 @@ + gcspr; \ + }) + +-static void __attribute__ ((noinline)) +-function1 (int arg) +-{ +- printf ("Called function1 with argument %d\n", arg); +-} +- + int + main (void) + { +- unsigned long gcs_mode, *gcspr; +- int ret; +- + if (!(getauxval (AT_HWCAP2) & HWCAP2_GCS)) + 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. +- */ +- ret = my_syscall2 (__NR_prctl, PR_GET_SHADOW_STACK_STATUS, &gcs_mode); ++ /* 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); +@@ -104,13 +98,21 @@ main (void) + } + } + +- function1 (1); /* break here */ ++ unsigned long *gcspr = get_gcspr (); ++ ++ /* Do something with gcspr, to make sure it isn't compiled out. */ ++ printf ("gcspr = %p\n", gcspr); /* break here */ + +- gcspr = get_gcspr (); ++ unsigned long *stack = (unsigned long *) syscall (__NR_map_shadow_stack, ++ 0 /* address */, ++ sysconf (_SC_PAGE_SIZE) /* size */, ++ 0 /* flags */); ++ if (stack == MAP_FAILED) ++ exit (EXIT_FAILURE); + + /* Cause a SEGV. */ +- *gcspr = 1; ++ *stack = 1; + +- /* Avoid returning in case libc doesn't understand GCS */ ++ /* 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 +index c207c62be8f..a6baba0a12e 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs.exp ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs.exp +@@ -30,5 +30,10 @@ if ![runto ${linespec}] { + } + + gdb_test "print \$gcspr" ". = \\(void \\*\\) $hex" "GDB knows about GCSPR" ++gdb_test "print \$gcspr == gcspr" ". = 1" "GDB has the correct GCSPR value" + +-gdb_test "next" "signal \\(SIGSEGV.*" "next to signal" ++gdb_test "continue" \ ++ ".*\r\nProgram received signal SIGSEGV, Segmentation fault\\..*stack = 1;" \ ++ "continue to SEGV" ++gdb_test "print \$_siginfo.si_code" ". = 10" \ ++ "Test value of si_code when GCS SIGSEGV happens" +-- +2.25.1 + + +From 8e05d6fe003c283c381cc0d92c6aac6eec6199b0 Mon Sep 17 00:00:00 2001 +From: Thiago Jung Bauermann +Date: Thu, 28 Dec 2023 00:25:07 -0300 +Subject: [PATCH 06/27] gdb.arch/aarch64-gcs.exp: Simplify the testcase a bit. + +--- + gdb/testsuite/gdb.arch/aarch64-gcs.c | 20 ++------------------ + gdb/testsuite/gdb.arch/aarch64-gcs.exp | 6 +++--- + 2 files changed, 5 insertions(+), 21 deletions(-) + +diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs.c b/gdb/testsuite/gdb.arch/aarch64-gcs.c +index 9c3b67619ad..a3c6de2032c 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs.c ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs.c +@@ -18,9 +18,7 @@ + #include + #include + #include +-#include + #include +-#include + #include + + /* Feature check for Guarded Control Stack. */ +@@ -34,10 +32,6 @@ + #define PR_SHADOW_STACK_ENABLE (1UL << 0) + #endif + +-#ifndef __NR_map_shadow_stack +-#define __NR_map_shadow_stack 453 +-#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. */ +@@ -100,18 +94,8 @@ main (void) + + unsigned long *gcspr = get_gcspr (); + +- /* Do something with gcspr, to make sure it isn't compiled out. */ +- printf ("gcspr = %p\n", gcspr); /* break here */ +- +- unsigned long *stack = (unsigned long *) syscall (__NR_map_shadow_stack, +- 0 /* address */, +- sysconf (_SC_PAGE_SIZE) /* size */, +- 0 /* flags */); +- if (stack == MAP_FAILED) +- exit (EXIT_FAILURE); +- +- /* Cause a SEGV. */ +- *stack = 1; ++ /* Cause a SIGSEGV. */ ++ *gcspr = 1; + + /* 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 +index a6baba0a12e..375eaa05e36 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs.exp ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs.exp +@@ -23,7 +23,7 @@ if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } { + return -1 + } + +-set linespec ${srcfile}:[gdb_get_line_number "break here"] ++set linespec ${srcfile}:[gdb_get_line_number "Cause a SIGSEGV"] + + if ![runto ${linespec}] { + return +@@ -33,7 +33,7 @@ gdb_test "print \$gcspr" ". = \\(void \\*\\) $hex" "GDB knows about GCSPR" + gdb_test "print \$gcspr == gcspr" ". = 1" "GDB has the correct GCSPR value" + + gdb_test "continue" \ +- ".*\r\nProgram received signal SIGSEGV, Segmentation fault\\..*stack = 1;" \ +- "continue to SEGV" ++ ".*\r\nProgram received signal SIGSEGV, Segmentation fault\\..*gcspr = 1;" \ ++ "continue to SIGSEGV" + gdb_test "print \$_siginfo.si_code" ". = 10" \ + "Test value of si_code when GCS SIGSEGV happens" +-- +2.25.1 + + +From 21ee3d1aa8bf5baee7b95982d9f945f60a806254 Mon Sep 17 00:00:00 2001 +From: Thiago Jung Bauermann +Date: Thu, 28 Dec 2023 23:52:18 -0300 +Subject: [PATCH 07/27] gdb.arch/aarch64-gcs.exp: Finally cause SIGSEGV with + the GCS-specific si_code. + +--- + gdb/testsuite/gdb.arch/aarch64-gcs.c | 17 +++++++++++++++-- + gdb/testsuite/gdb.arch/aarch64-gcs.exp | 4 ++-- + 2 files changed, 17 insertions(+), 4 deletions(-) + +diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs.c b/gdb/testsuite/gdb.arch/aarch64-gcs.c +index a3c6de2032c..17b4c6cbb02 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs.c ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs.c +@@ -61,6 +61,19 @@ + 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)); ++ ++ /* Cause a GCS exception. */ ++ x30 = 0; ++ __asm__ volatile("ret\n"); ++} ++ + int + main (void) + { +@@ -94,8 +107,8 @@ main (void) + + unsigned long *gcspr = get_gcspr (); + +- /* Cause a SIGSEGV. */ +- *gcspr = 1; ++ /* 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.exp b/gdb/testsuite/gdb.arch/aarch64-gcs.exp +index 375eaa05e36..d52b84c4d6f 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs.exp ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs.exp +@@ -23,7 +23,7 @@ if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } { + return -1 + } + +-set linespec ${srcfile}:[gdb_get_line_number "Cause a SIGSEGV"] ++set linespec ${srcfile}:[gdb_get_line_number "Break here"] + + if ![runto ${linespec}] { + return +@@ -33,7 +33,7 @@ gdb_test "print \$gcspr" ". = \\(void \\*\\) $hex" "GDB knows about GCSPR" + gdb_test "print \$gcspr == gcspr" ". = 1" "GDB has the correct GCSPR value" + + gdb_test "continue" \ +- ".*\r\nProgram received signal SIGSEGV, Segmentation fault\\..*gcspr = 1;" \ ++ {.*\r\nProgram received signal SIGSEGV, Segmentation fault\..*__asm__ volatile\("ret\\n"\);} \ + "continue to SIGSEGV" + gdb_test "print \$_siginfo.si_code" ". = 10" \ + "Test value of si_code when GCS SIGSEGV happens" +-- +2.25.1 + + +From 6e6125d9c190dff9db27c565b90e8dc750f543dc Mon Sep 17 00:00:00 2001 +From: Thiago Jung Bauermann +Date: Tue, 2 Jan 2024 22:57:45 -0300 +Subject: [PATCH 08/27] gdb.arch/aarch64-gcs.exp: Test unwinding of signal + frame GCS context + +Unfortunately one tests fails: + + #5 0x0000aaaaaaaa0ac4 in main () at /home/bauermann/src/binutils-gdb/gdb/testsuite/gdb.arch/aarch64-gcs.c:128 + 128 raise (SIGUSR1); + (gdb) print $gcspr + $3 = (void *) 0xfffff7e0ffe0 + (gdb) PASS: gdb.arch/aarch64-gcs.exp: GCSPR unwound from signal frame + print $gcspr_in_main == $gcspr + $4 = 0 + (gdb) FAIL: gdb.arch/aarch64-gcs.exp: Unwound GCSPR is correct +--- + gdb/testsuite/gdb.arch/aarch64-gcs.c | 24 +++++++++++- + gdb/testsuite/gdb.arch/aarch64-gcs.exp | 52 ++++++++++++++++++++++++++ + 2 files changed, 74 insertions(+), 2 deletions(-) + +diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs.c b/gdb/testsuite/gdb.arch/aarch64-gcs.c +index 17b4c6cbb02..c187528c448 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs.c ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs.c +@@ -17,6 +17,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -61,6 +62,14 @@ + gcspr; \ + }) + ++static unsigned long *handler_gcspr = 0; ++ ++static void ++handler (int sig) ++{ ++ handler_gcspr = get_gcspr (); ++} ++ + /* Corrupt the return address to see if GDB will report a SIGSEGV with the expected + $_siginfo.si_code. */ + static void __attribute__ ((noinline)) +@@ -70,7 +79,7 @@ function (unsigned long *gcspr) + register long x30 __asm__("x30") __attribute__ ((unused)); + + /* Cause a GCS exception. */ +- x30 = 0; ++ x30 = 0xbadc0ffee; + __asm__ volatile("ret\n"); + } + +@@ -107,8 +116,19 @@ main (void) + + 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); ++ + /* Pass gscpr to function just so it's used for something. */ +- function (gcspr); /* Break here. */ ++ function (gcspr); + + /* 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 +index d52b84c4d6f..22461d5d947 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs.exp ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs.exp +@@ -31,9 +31,61 @@ if ![runto ${linespec}] { + + 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 for later" ++ ++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" ++ ++set frame_levels 0 ++# Go to main's frame, or at least stop at the most outer frame possible ++while { $frame_levels < 10 } { ++ gdb_test_multiple "up" "" { ++ -re -wrap "#\[0-9\]+ main \\(\\)\r\n\\s+at .*aarch64-gcs.c:\[0-9\]+\r\n\[0-9\]+\s+raise \(SIGUSR1\);" { ++ # We're done. ++ break ++ } ++ -re -wrap "#\[0-9\]+ " { ++ # Matches the signal handler frame. ++ # Continue iterating. ++ } ++ -re -wrap "#\[0-9\]+ $hex in \S+ \\(\\)" { ++ # Matches frame without debug information. ++ # Continue iterating. ++ } ++ -re -wrap "#\[0-9\]+ (?:$hex in )?\\S+ \\(.*\\) at .*\\S+:\[0-9\]+\r\n(?:warning:.*: No such file or directory|\[0-9\]+\\s+in \\S+)" { ++ # Matches frame with debug information. We may not have source code ++ # for system libraries though. ++ # Continue iterating. ++ } ++ -re -wrap "\[^\r\n\]+" { ++ # Unexpected output. Maybe can't unwind frame any further? ++ break; ++ } ++ } ++ ++ incr frame_levels ++} ++ ++if { $frame_levels > 0 } { ++ gdb_test "print \$gcspr" ". = \\(void \\*\\) $hex" \ ++ "GCSPR unwound from signal frame" ++ gdb_test "print \$gcspr_in_main == \$gcspr" ". = 1" \ ++ "Unwound GCSPR is correct" ++} else { ++ # We can't test unwinding GCSPR from the signal frame in this case. ++ fail "Unable to unwind signal handler stack" ++} + + gdb_test "continue" \ + {.*\r\nProgram received signal SIGSEGV, Segmentation fault\..*__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. ++gdb_test "print \$gcspr == \$gcspr_in_main - 8" ". = 1" \ ++ "Test value of GCSPR when GCS SIGSEGV happens" +-- +2.25.1 + + +From d98f955aa34fc33fb5dafe46b3409f8ff01140ca Mon Sep 17 00:00:00 2001 +From: Thiago Jung Bauermann +Date: Wed, 3 Jan 2024 22:45:58 -0300 +Subject: [PATCH 09/27] gdb.arch/aarch64-gcs.exp: Fix testing of GCSPR in + signal context + +I realised that if the inferior doesn't save the GCSPR in its function +prologues, then GDB can't unwind it all the way back to the main frame. + +Therefore, test it just above the special frame. +--- + gdb/testsuite/gdb.arch/aarch64-gcs.exp | 52 ++++++-------------------- + 1 file changed, 12 insertions(+), 40 deletions(-) + +diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs.exp b/gdb/testsuite/gdb.arch/aarch64-gcs.exp +index 22461d5d947..f57f6c5043d 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs.exp ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs.exp +@@ -31,7 +31,8 @@ if ![runto ${linespec}] { + + 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 for later" ++gdb_test_no_output "set \$gcspr_in_main = \$gcspr" \ ++ "Save GCSPR value in main for later" + + gdb_test "break handler" "Breakpoint \[0-9\]+ .*aarch64-gcs.c, line \[0-9\]+\\." + gdb_test "handle SIGUSR1 nostop" \ +@@ -41,45 +42,16 @@ gdb_test "continue" \ + ".*\r\nBreakpoint \[0-9\]+, handler \\(sig=10\\) at .*aarch64-gcs.c.*handler_gcspr = get_gcspr \\(\\);" \ + "continue to signal handler" + +-set frame_levels 0 +-# Go to main's frame, or at least stop at the most outer frame possible +-while { $frame_levels < 10 } { +- gdb_test_multiple "up" "" { +- -re -wrap "#\[0-9\]+ main \\(\\)\r\n\\s+at .*aarch64-gcs.c:\[0-9\]+\r\n\[0-9\]+\s+raise \(SIGUSR1\);" { +- # We're done. +- break +- } +- -re -wrap "#\[0-9\]+ " { +- # Matches the signal handler frame. +- # Continue iterating. +- } +- -re -wrap "#\[0-9\]+ $hex in \S+ \\(\\)" { +- # Matches frame without debug information. +- # Continue iterating. +- } +- -re -wrap "#\[0-9\]+ (?:$hex in )?\\S+ \\(.*\\) at .*\\S+:\[0-9\]+\r\n(?:warning:.*: No such file or directory|\[0-9\]+\\s+in \\S+)" { +- # Matches frame with debug information. We may not have source code +- # for system libraries though. +- # Continue iterating. +- } +- -re -wrap "\[^\r\n\]+" { +- # Unexpected output. Maybe can't unwind frame any further? +- break; +- } +- } +- +- incr frame_levels +-} +- +-if { $frame_levels > 0 } { +- gdb_test "print \$gcspr" ". = \\(void \\*\\) $hex" \ +- "GCSPR unwound from signal frame" +- gdb_test "print \$gcspr_in_main == \$gcspr" ". = 1" \ +- "Unwound GCSPR is correct" +-} else { +- # We can't test unwinding GCSPR from the signal frame in this case. +- fail "Unable to unwind signal handler stack" +-} ++gdb_test_no_output "set \$gcspr_in_handler = \$gcspr" \ ++ "Save GCSPR value in handler for later" ++# Select the frame above the frame, which makes GDB ++# unwind the GCSPR from the signal frame GCS context. ++gdb_test "frame 2" \ ++ "#2 ($hex in )?\\S+ \\(.*\\) (at|from) \\S+(\r\n(warning:.*: No such file or directory|\[0-9\]+\\s+in \\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" \ + {.*\r\nProgram received signal SIGSEGV, Segmentation fault\..*__asm__ volatile\("ret\\n"\);} \ +-- +2.25.1 + + +From 4d7e2c852fc8558c30409c52dd28346fa62c0e03 Mon Sep 17 00:00:00 2001 +From: Thiago Jung Bauermann +Date: Fri, 5 Jan 2024 18:54:38 -0300 +Subject: [PATCH 10/27] bfd/aarch64-linux: Add support for reading and writing + the GCS core file note + +--- + bfd/elf-bfd.h | 2 ++ + bfd/elf.c | 28 ++++++++++++++++++++++++++++ + 2 files changed, 30 insertions(+) + +diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h +index b89d3dda05d..325a0aa859e 100644 +--- a/bfd/elf-bfd.h ++++ b/bfd/elf-bfd.h +@@ -2982,6 +2982,8 @@ extern char *elfcore_write_aarch_za + (bfd *, char *, int *, const void *, int); + extern char *elfcore_write_aarch_zt + (bfd *, char *, int *, const void *, int); ++extern char *elfcore_write_aarch_gcs ++ (bfd *, char *, int *, const void *_gcs, int); + extern char *elfcore_write_arc_v2 + (bfd *, char *, int *, const void *, int); + extern char *elfcore_write_riscv_csr +diff --git a/bfd/elf.c b/bfd/elf.c +index f85f79e1e35..1de08abc209 100644 +--- a/bfd/elf.c ++++ b/bfd/elf.c +@@ -10584,6 +10584,15 @@ elfcore_grok_aarch_zt (bfd *abfd, Elf_Internal_Note *note) + return elfcore_make_note_pseudosection (abfd, ".reg-aarch-zt", note); + } + ++/* Convert NOTE into a bfd_section called ".reg-aarch-gcs". Return TRUE if ++ successful, otherwise return FALSE. */ ++ ++static bool ++elfcore_grok_aarch_gcs (bfd *abfd, Elf_Internal_Note *note) ++{ ++ return elfcore_make_note_pseudosection (abfd, ".reg-aarch-gcs", note); ++} ++ + static bool + elfcore_grok_arc_v2 (bfd *abfd, Elf_Internal_Note *note) + { +@@ -11320,6 +11329,12 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note) + else + return true; + ++ case NT_ARM_GCS: ++ if (note->namesz == 6 && strcmp (note->namedata, "LINUX") == 0) ++ return elfcore_grok_aarch_gcs (abfd, note); ++ else ++ return true; ++ + case NT_GDB_TDESC: + if (note->namesz == 4 + && strcmp (note->namedata, "GDB") == 0) +@@ -12981,6 +12996,17 @@ elfcore_write_aarch_zt (bfd *abfd, + size); + } + ++/* FIXME: Document. */ ++ ++char * ++elfcore_write_aarch_gcs (bfd *abfd, char *buf, int *bufsiz, ++ const void *aarch_gcs, int size) ++{ ++ char *note_name = "LINUX"; ++ return elfcore_write_note (abfd, buf, bufsiz, note_name, NT_ARM_GCS, ++ aarch_gcs, size); ++} ++ + char * + elfcore_write_arc_v2 (bfd *abfd, + char *buf, +@@ -13168,6 +13194,8 @@ elfcore_write_register_note (bfd *abfd, + return elfcore_write_aarch_za (abfd, buf, bufsiz, data, size); + if (strcmp (section, ".reg-aarch-zt") == 0) + return elfcore_write_aarch_zt (abfd, buf, bufsiz, data, size); ++ if (strcmp (section, ".reg-aarch-gcs") == 0) ++ return elfcore_write_aarch_gcs (abfd, buf, bufsiz, data, size); + if (strcmp (section, ".reg-arc-v2") == 0) + return elfcore_write_arc_v2 (abfd, buf, bufsiz, data, size); + if (strcmp (section, ".gdb-tdesc") == 0) +-- +2.25.1 + + +From 02fb282e3671098b7ccc251fe2e451f402975d0e Mon Sep 17 00:00:00 2001 +From: Thiago Jung Bauermann +Date: Mon, 8 Jan 2024 17:31:05 -0300 +Subject: [PATCH 11/27] gdb.arch/aarch64-gcs-core.exp: New test +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +There's one failure: + +print/x $gcspr +$1 = 0x1 +(gdb) FAIL: gdb.arch/aarch64-gcs-core.exp: native corefile: gcspr contents from core file + +Apparently the kernel¹ isn't saving the GCSPR correctly in the core file. + +¹ 6.7.0-rc2-00047-gc16ba0f4123b, with GCS patches v7. +--- + gdb/testsuite/gdb.arch/aarch64-gcs-core.c | 116 ++++++++++++++++++++ + gdb/testsuite/gdb.arch/aarch64-gcs-core.exp | 90 +++++++++++++++ + 2 files changed, 206 insertions(+) + create mode 100644 gdb/testsuite/gdb.arch/aarch64-gcs-core.c + create mode 100644 gdb/testsuite/gdb.arch/aarch64-gcs-core.exp + +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 00000000000..0658a6b7b51 +--- /dev/null ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs-core.c +@@ -0,0 +1,116 @@ ++/* This test program 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 . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* Feature check for Guarded Control Stack. */ ++#ifndef HWCAP2_GCS ++#define HWCAP2_GCS (1UL << 48) ++#endif ++ ++#ifndef PR_GET_SHADOW_STACK_STATUS ++#define PR_GET_SHADOW_STACK_STATUS 71 ++#define PR_SET_SHADOW_STACK_STATUS 72 ++#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; \ ++ \ ++ 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)); ++ ++ /* Cause a GCS exception. */ ++ x30 = 0xbadc0ffee; ++ __asm__ volatile("ret\n"); ++} ++ ++int ++main (void) ++{ ++ if (!(getauxval (AT_HWCAP2) & HWCAP2_GCS)) ++ 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 00000000000..a0c81b789c6 +--- /dev/null ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs-core.exp +@@ -0,0 +1,90 @@ ++# 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 . ++ ++# Test reading and writing the core dump of a binary that uses a Guarded Control ++# Stack. ++ ++proc check_core_file {core_filename saved_gcspr} { ++ # 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 .*" \ ++ "\[0-9\]+.*__asm__ volatile\\(\"ret\\\\n\"\\);"] \ ++ "load core file"] { ++ untested "failed to load core file" ++ return -1 ++ } ++ ++ # Check the value of TPIDR2 in the core file. ++ gdb_test "print/x \$gcspr" "\\$\[0-9\]+ = $saved_gcspr" \ ++ "gcspr contents from core file" ++} ++ ++require allow_aarch64_gcs_tests ++ ++standard_testfile ++ ++if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } { ++ return -1 ++} ++ ++set linespec ${srcfile}:[gdb_get_line_number "Break here"] ++ ++if ![runto ${linespec}] { ++ return ++} ++ ++# Continue until a crash. ++gdb_test "continue" \ ++ {.*\r\nProgram received signal SIGSEGV, Segmentation fault\..*__asm__ volatile\("ret\\n"\);} \ ++ "continue to SIGSEGV" ++ ++set gcspr_at_segv [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"] ++ ++# Generate a native core file. ++set core_filename [core_find ${binfile} {} {}] ++set core_generated [expr {$core_filename != ""}] ++set native_core_name "${binfile}.core" ++remote_exec build "mv $core_filename ${native_core_name}" ++set core_filename ${native_core_name} ++ ++# At this point we have a couple of core files, the gcore one generated by ++# GDB and the native one generated by the Linux kernel. Make sure GDB can ++# read both correctly. ++if {$gcore_generated} { ++ clean_restart ${binfile} ++ ++ with_test_prefix "gcore corefile" { ++ check_core_file $gcore_filename $gcspr_at_segv ++ } ++} else { ++ fail "gcore corefile not generated" ++} ++ ++if {$core_generated} { ++ clean_restart ${binfile} ++ ++ with_test_prefix "native corefile" { ++ check_core_file $core_filename $gcspr_at_segv ++ } ++} else { ++ untested "native corefile not generated" ++} +-- +2.25.1 + + +From bea69037da4f7831019044942c765f85893163b7 Mon Sep 17 00:00:00 2001 +From: Thiago Jung Bauermann +Date: Sat, 3 Feb 2024 15:40:51 -0300 +Subject: [PATCH 12/27] gdb/aarch64-linux: Fix core file offset for the GCSPR. + +--- + gdb/aarch64-linux-tdep.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c +index ff08913cf09..60bfddd840a 100644 +--- a/gdb/aarch64-linux-tdep.c ++++ b/gdb/aarch64-linux-tdep.c +@@ -1669,6 +1669,8 @@ aarch64_linux_iterate_over_regset_sections (struct gdbarch *gdbarch, + /* Create this on the fly in order to handle the variable location. */ + const struct regcache_map_entry gcs_regmap[] = + { ++ { 1, REGCACHE_MAP_SKIP, 8 }, /* features_enabled */ ++ { 1, REGCACHE_MAP_SKIP, 8 }, /* features_locked */ + { 1, tdep->gcs_reg_base, 8 }, + { 0 } + }; +-- +2.25.1 + + +From 586e825f7dfcd9d3550d503b2d18c39ff4851cfb Mon Sep 17 00:00:00 2001 +From: Thiago Jung Bauermann +Date: Sat, 3 Feb 2024 18:09:52 -0300 +Subject: [PATCH 13/27] gdb.arch/aarch64-gcs-core: Fix test of kernel-generated + core file. + +--- + gdb/testsuite/gdb.arch/aarch64-gcs-core.c | 4 ++++ + gdb/testsuite/gdb.arch/aarch64-gcs-core.exp | 12 ++++++++---- + gdb/testsuite/lib/gdb.exp | 4 ++-- + 3 files changed, 14 insertions(+), 6 deletions(-) + +diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs-core.c b/gdb/testsuite/gdb.arch/aarch64-gcs-core.c +index 0658a6b7b51..7508f7b77fa 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs-core.c ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs-core.c +@@ -70,6 +70,10 @@ 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"); +diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs-core.exp b/gdb/testsuite/gdb.arch/aarch64-gcs-core.exp +index a0c81b789c6..f97650b6bdd 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs-core.exp ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs-core.exp +@@ -53,14 +53,14 @@ gdb_test "continue" \ + {.*\r\nProgram received signal SIGSEGV, Segmentation fault\..*__asm__ volatile\("ret\\n"\);} \ + "continue to SIGSEGV" + +-set gcspr_at_segv [get_valueof "/x" "\$gcspr" "*unknown*"] ++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"] + + # Generate a native core file. +-set core_filename [core_find ${binfile} {} {}] ++set core_filename [core_find ${binfile} {} {} "${binfile}.out"] + set core_generated [expr {$core_filename != ""}] + set native_core_name "${binfile}.core" + remote_exec build "mv $core_filename ${native_core_name}" +@@ -73,7 +73,7 @@ if {$gcore_generated} { + clean_restart ${binfile} + + with_test_prefix "gcore corefile" { +- check_core_file $gcore_filename $gcspr_at_segv ++ check_core_file $gcore_filename $gcspr_in_gcore + } + } else { + fail "gcore corefile not generated" +@@ -83,7 +83,11 @@ if {$core_generated} { + clean_restart ${binfile} + + with_test_prefix "native corefile" { +- check_core_file $core_filename $gcspr_at_segv ++ 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 + } + } else { + untested "native corefile not generated" +diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp +index b5d35e6a4dc..7acb69e1910 100644 +--- a/gdb/testsuite/lib/gdb.exp ++++ b/gdb/testsuite/lib/gdb.exp +@@ -8958,7 +8958,7 @@ proc remove_core {pid {test ""}} { + } + } + +-proc core_find {binfile {deletefiles {}} {arg ""}} { ++proc core_find {binfile {deletefiles {}} {arg ""} {output_file "/dev/null"}} { + global objdir subdir + + set destcore "$binfile.core" +@@ -8980,7 +8980,7 @@ proc core_find {binfile {deletefiles {}} {arg ""}} { + set found 0 + set coredir [standard_output_file coredir.[getpid]] + file mkdir $coredir +- catch "system \"(cd ${coredir}; ulimit -c unlimited; ${binfile} ${arg}; true) >/dev/null 2>&1\"" ++ catch "system \"(cd ${coredir}; ulimit -c unlimited; ${binfile} ${arg}; true) >${output_file} 2>&1\"" + # remote_exec host "${binfile}" + foreach i "${coredir}/core ${coredir}/core.coremaker.c ${binfile}.core" { + if [remote_file build exists $i] { +-- +2.25.1 + + +From 357d0921cabdf9fb16b7193b0fb4c713988c8af7 Mon Sep 17 00:00:00 2001 +From: Thiago Jung Bauermann +Date: Sat, 3 Feb 2024 18:12:01 -0300 +Subject: [PATCH 14/27] gdb.arch/aarch64-gcs-core.exp: Move check_core_file + closer to use. + +--- + gdb/testsuite/gdb.arch/aarch64-gcs-core.exp | 37 +++++++++++---------- + 1 file changed, 19 insertions(+), 18 deletions(-) + +diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs-core.exp b/gdb/testsuite/gdb.arch/aarch64-gcs-core.exp +index f97650b6bdd..2fd9abb04c3 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs-core.exp ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs-core.exp +@@ -16,24 +16,6 @@ + # Test reading and writing the core dump of a binary that uses a Guarded Control + # Stack. + +-proc check_core_file {core_filename saved_gcspr} { +- # 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 .*" \ +- "\[0-9\]+.*__asm__ volatile\\(\"ret\\\\n\"\\);"] \ +- "load core file"] { +- untested "failed to load core file" +- return -1 +- } +- +- # Check the value of TPIDR2 in the core file. +- gdb_test "print/x \$gcspr" "\\$\[0-9\]+ = $saved_gcspr" \ +- "gcspr contents from core file" +-} +- + require allow_aarch64_gcs_tests + + standard_testfile +@@ -69,6 +51,25 @@ set core_filename ${native_core_name} + # At this point we have a couple of core files, the gcore one generated by + # GDB and the native one generated by the Linux kernel. Make sure GDB can + # read both correctly. ++ ++proc check_core_file {core_filename saved_gcspr} { ++ # 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 .*" \ ++ "\[0-9\]+.*__asm__ volatile\\(\"ret\\\\n\"\\);"] \ ++ "load core file"] { ++ untested "failed to load core file" ++ return -1 ++ } ++ ++ # Check the value of TPIDR2 in the core file. ++ gdb_test "print/x \$gcspr" "\\$\[0-9\]+ = $saved_gcspr" \ ++ "gcspr contents from core file" ++} ++ + if {$gcore_generated} { + clean_restart ${binfile} + +-- +2.25.1 + + +From 779bd7553c579d8a1c8e5264f754b20da4378c7b Mon Sep 17 00:00:00 2001 +From: Thiago Jung Bauermann +Date: Sat, 3 Feb 2024 18:12:57 -0300 +Subject: [PATCH 15/27] gdb.arch/aarch64-gcs-core.exp: Don't use unnecessary {} + around variables. + +--- + gdb/testsuite/gdb.arch/aarch64-gcs-core.exp | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs-core.exp b/gdb/testsuite/gdb.arch/aarch64-gcs-core.exp +index 2fd9abb04c3..ea79174aef0 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs-core.exp ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs-core.exp +@@ -20,13 +20,13 @@ require allow_aarch64_gcs_tests + + standard_testfile + +-if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } { ++if { [prepare_for_testing "failed to prepare" $testfile $srcfile] } { + return -1 + } + + set linespec ${srcfile}:[gdb_get_line_number "Break here"] + +-if ![runto ${linespec}] { ++if ![runto $linespec] { + return + } + +@@ -42,11 +42,11 @@ set gcore_filename [standard_output_file "${testfile}.gcore"] + set gcore_generated [gdb_gcore_cmd "$gcore_filename" "generate gcore file"] + + # Generate a native core file. +-set core_filename [core_find ${binfile} {} {} "${binfile}.out"] ++set core_filename [core_find $binfile {} {} "${binfile}.out"] + set core_generated [expr {$core_filename != ""}] + set native_core_name "${binfile}.core" +-remote_exec build "mv $core_filename ${native_core_name}" +-set core_filename ${native_core_name} ++remote_exec build "mv $core_filename $native_core_name" ++set core_filename $native_core_name + + # At this point we have a couple of core files, the gcore one generated by + # GDB and the native one generated by the Linux kernel. Make sure GDB can +@@ -71,7 +71,7 @@ proc check_core_file {core_filename saved_gcspr} { + } + + if {$gcore_generated} { +- clean_restart ${binfile} ++ clean_restart $binfile + + with_test_prefix "gcore corefile" { + check_core_file $gcore_filename $gcspr_in_gcore +@@ -81,7 +81,7 @@ if {$gcore_generated} { + } + + if {$core_generated} { +- clean_restart ${binfile} ++ clean_restart $binfile + + with_test_prefix "native corefile" { + set out_id [open ${binfile}.out "r"] +-- +2.25.1 + + +From ff013e24ff2437674c3e40a2d69ec6a78477760f Mon Sep 17 00:00:00 2001 +From: Thiago Jung Bauermann +Date: Wed, 7 Feb 2024 18:16:24 -0300 +Subject: [PATCH 16/27] Report when a SIGSEGV happens because of GCS. + +--- + gdb/aarch64-linux-tdep.c | 18 ++++++++++++------ + gdb/arch/aarch64-gcs-linux.h | 4 ++++ + gdb/testsuite/gdb.arch/aarch64-gcs-core.exp | 20 +++++++++++++++----- + gdb/testsuite/gdb.arch/aarch64-gcs.exp | 8 +++++++- + 4 files changed, 38 insertions(+), 12 deletions(-) + +diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c +index 60bfddd840a..04bc46245f2 100644 +--- a/gdb/aarch64-linux-tdep.c ++++ b/gdb/aarch64-linux-tdep.c +@@ -2682,17 +2682,18 @@ aarch64_linux_report_signal_info (struct gdbarch *gdbarch, + { + aarch64_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + +- if (!tdep->has_mte () || siggnal != GDB_SIGNAL_SEGV) ++ if (!(tdep->has_mte () || tdep->has_gcs ()) || siggnal != GDB_SIGNAL_SEGV) + return; + + CORE_ADDR fault_addr = 0; +- long si_code = 0; ++ long si_code = 0, si_errno = 0; + + try + { + /* Sigcode tells us if the segfault is actually a memory tag + violation. */ + si_code = parse_and_eval_long ("$_siginfo.si_code"); ++ si_errno = parse_and_eval_long ("$_siginfo.si_errno"); + + fault_addr + = parse_and_eval_long ("$_siginfo._sifields._sigfault.si_addr"); +@@ -2703,13 +2704,18 @@ aarch64_linux_report_signal_info (struct gdbarch *gdbarch, + return; + } + +- /* If this is not a memory tag violation, just return. */ +- if (si_code != SEGV_MTEAERR && si_code != SEGV_MTESERR) ++ const char *meaning; ++ ++ if (si_code == SEGV_MTEAERR || si_code == SEGV_MTESERR) ++ meaning = _("Memory tag violation"); ++ else if (si_code == SEGV_CPERR && si_errno == 0) ++ meaning = _("Guarded Control Stack error"); ++ else + return; + + uiout->text ("\n"); + +- uiout->field_string ("sigcode-meaning", _("Memory tag violation")); ++ uiout->field_string ("sigcode-meaning", meaning); + + /* For synchronous faults, show additional information. */ + if (si_code == SEGV_MTESERR) +@@ -2734,7 +2740,7 @@ aarch64_linux_report_signal_info (struct gdbarch *gdbarch, + uiout->field_string ("logical-tag", hex_string (ltag)); + } + } +- else ++ else if (si_code != SEGV_CPERR) + { + uiout->text ("\n"); + uiout->text (_("Fault address unavailable")); +diff --git a/gdb/arch/aarch64-gcs-linux.h b/gdb/arch/aarch64-gcs-linux.h +index 65f70a72b15..761c498b76a 100644 +--- a/gdb/arch/aarch64-gcs-linux.h ++++ b/gdb/arch/aarch64-gcs-linux.h +@@ -44,4 +44,8 @@ struct user_gcs + + #endif /* GCS_MAGIC */ + ++#ifndef SEGV_CPERR ++#define SEGV_CPERR 10 /* Control protection error. */ ++#endif ++ + #endif /* ARCH_AARCH64_GCS_LINUX_H */ +diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs-core.exp b/gdb/testsuite/gdb.arch/aarch64-gcs-core.exp +index ea79174aef0..73db3c1a87c 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs-core.exp ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs-core.exp +@@ -32,7 +32,14 @@ if ![runto $linespec] { + + # Continue until a crash. + gdb_test "continue" \ +- {.*\r\nProgram received signal SIGSEGV, Segmentation fault\..*__asm__ volatile\("ret\\n"\);} \ ++ [multi_line \ ++ "Continuing\\." \ ++ "$hex" \ ++ "" \ ++ "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*"] +@@ -53,13 +60,16 @@ set core_filename $native_core_name + # read both 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\." \ +- "#0 function \\(.*\\) at .*" \ +- "\[0-9\]+.*__asm__ volatile\\(\"ret\\\\n\"\\);"] \ ++ "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"] { + untested "failed to load core file" + return -1 +diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs.exp b/gdb/testsuite/gdb.arch/aarch64-gcs.exp +index f57f6c5043d..8d5f6e90c25 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs.exp ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs.exp +@@ -54,8 +54,14 @@ gdb_test "print \$gcspr == \$gcspr_in_handler + 8" ". = 1" \ + "GCSPR unwound from signal context is correct" + + gdb_test "continue" \ +- {.*\r\nProgram received signal SIGSEGV, Segmentation fault\..*__asm__ volatile\("ret\\n"\);} \ ++ [multi_line \ ++ "Continuing\\." \ ++ "" \ ++ "Program received signal SIGSEGV, Segmentation fault" \ ++ "Guarded Control Stack error\\." \ ++ {.*__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. +-- +2.25.1 + + +From 6ff5e6aa1064c8f8fd8fc08963efbe2a1a5e7a8e Mon Sep 17 00:00:00 2001 +From: Thiago Jung Bauermann +Date: Wed, 28 Feb 2024 21:34:04 -0300 +Subject: [PATCH 17/27] Install gdbarch_report_signal_info hook when target + supports GCS + +Fixes GCS signal info not being printed after updating Shrinkwrap image. +--- + gdb/aarch64-linux-tdep.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c +index 04bc46245f2..f9b743f4810 100644 +--- a/gdb/aarch64-linux-tdep.c ++++ b/gdb/aarch64-linux-tdep.c +@@ -3003,9 +3003,6 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) + /* Register a hook for converting a memory tag to a string. */ + set_gdbarch_memtag_to_string (gdbarch, aarch64_linux_memtag_to_string); + +- set_gdbarch_report_signal_info (gdbarch, +- aarch64_linux_report_signal_info); +- + /* Core file helpers. */ + + /* Core file helper to create a memory tag section for a particular +@@ -3022,6 +3019,9 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) + aarch64_linux_decode_memtag_section); + } + ++ if (tdep->has_mte () || tdep->has_gcs ()) ++ set_gdbarch_report_signal_info (gdbarch, aarch64_linux_report_signal_info); ++ + /* Initialize the aarch64_linux_record_tdep. */ + /* These values are the size of the type that will be used in a system + call. They are obtained from Linux Kernel source. */ +-- +2.25.1 + + +From 6501de854b2269802d043309a651b33b47bf45a9 Mon Sep 17 00:00:00 2001 +From: Thiago Jung Bauermann +Date: Sat, 17 Feb 2024 13:37:11 -0300 +Subject: [PATCH 18/27] Add "PC" flag to show in backtrace when the GCS has a + different return address + +The test needs to use "backtrace -frame-info location-and-address" because +by default GDB doesn't call gdbarch_get_pc_address_flags () for some +frames, depending on where the PC is at within the source line, and whether +there is debug info for the function. + +Because of this, a better alternative is to add separate frame +flags/decoration to show the GCS error message. +--- + gdb/aarch64-tdep.c | 58 +++++++++++++++++++++++++- + gdb/testsuite/gdb.arch/aarch64-gcs.c | 2 +- + gdb/testsuite/gdb.arch/aarch64-gcs.exp | 6 +++ + 3 files changed, 63 insertions(+), 3 deletions(-) + +diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c +index 0d32b948924..4fd545e7efa 100644 +--- a/gdb/aarch64-tdep.c ++++ b/gdb/aarch64-tdep.c +@@ -301,15 +301,69 @@ aarch64_frame_unmask_lr (aarch64_gdbarch_tdep *tdep, + return addr; + } + ++static std::optional ++aarch64_get_gcs_flag (frame_info_ptr frame) ++{ ++ int frame_level = frame_relative_level (frame); ++ if (frame_level < 0) ++ return {}; ++ ++ /* GCS is only available for real frames. */ ++ if (get_frame_id (frame).artificial_depth > 0) ++ return {}; ++ ++ /* The GCSPR isn't saved in the stack, so we get it from the live register ++ file. */ ++ /* FIXME: Is there a way to get the inferior corresponding to the given ++ frame? */ ++ struct regcache *regcache = get_thread_regcache (inferior_thread ()); ++ aarch64_gdbarch_tdep *tdep ++ = gdbarch_tdep (regcache->arch ()); ++ CORE_ADDR gcspr; ++ ++ if (!tdep->has_gcs ()) ++ return {}; ++ ++ if (regcache->cooked_read (tdep->gcs_reg_base, &gcspr) != REG_VALID) ++ return {}; ++ ++ gdb_byte buf[8]; ++ /* Read the GCS return address entry corresponding to this stack frame. */ ++ if (target_read_memory (gcspr + 8 * frame_level, buf, sizeof (buf)) != 0) ++ return {}; ++ ++ bfd_endian byte_order = gdbarch_byte_order (regcache->arch ()); ++ CORE_ADDR gcs_lr = extract_integer (buf, byte_order); ++ ++ get_frame_register (frame, AARCH64_LR_REGNUM, buf); ++ CORE_ADDR lr = extract_integer (buf, byte_order); ++ ++ if (gcs_lr == lr) ++ return {}; ++ else ++ return "GCS error"; ++} ++ + /* Implement the "get_pc_address_flags" gdbarch method. */ + + static std::string + aarch64_get_pc_address_flags (const frame_info_ptr &frame, CORE_ADDR pc) + { ++ std::string ret; ++ + if (pc != 0 && get_frame_pc_masked (frame)) +- return "PAC"; ++ ret += "PAC"; ++ ++ std::optional gcs_flag = aarch64_get_gcs_flag (frame); ++ if (gcs_flag.has_value ()) ++ { ++ if (!ret.empty()) ++ ret += " "; + +- return ""; ++ ret += *gcs_flag; ++ } ++ ++ return ret; + } + + /* Analyze a prologue, looking for a recognizable stack frame +diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs.c b/gdb/testsuite/gdb.arch/aarch64-gcs.c +index c187528c448..9cba9fa63bc 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs.c ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs.c +@@ -76,7 +76,7 @@ static void __attribute__ ((noinline)) + function (unsigned long *gcspr) + { + /* x30 holds the return address. */ +- register long x30 __asm__("x30") __attribute__ ((unused)); ++ register unsigned long x30 __asm__("x30") __attribute__ ((unused)); + + /* Cause a GCS exception. */ + x30 = 0xbadc0ffee; +diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs.exp b/gdb/testsuite/gdb.arch/aarch64-gcs.exp +index 8d5f6e90c25..fed1f28ad85 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs.exp ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs.exp +@@ -67,3 +67,9 @@ gdb_test "print \$_siginfo.si_code" ". = 10" \ + # The GCS grows down. + gdb_test "print \$gcspr == \$gcspr_in_main - 8" ". = 1" \ + "Test value of GCSPR when GCS SIGSEGV happens" ++ ++gdb_test "backtrace -frame-info location-and-address" \ ++ [multi_line \ ++ "#0 $hex \\\[GCS error\\\] in function \\(gcspr=$hex\\) at .*aarch64-gcs.c:$decimal" \ ++ "#1 $hex \\\[GCS error\\\] in main \\(\\) at .*aarch64-gcs.c:$decimal"] \ ++ "GCS flag in backtrace" +-- +2.25.1 + + +From a430660e6196af01a941ab682ecb9cf88906ced7 Mon Sep 17 00:00:00 2001 +From: Thiago Jung Bauermann +Date: Wed, 28 Feb 2024 21:15:11 -0300 +Subject: [PATCH 19/27] Add concept of frame flags, and convert GCS error to + use it + +This fixes two problems with the GCS error as a PC flag: + +1. It's not about the PC, but about the return value saved in the frame. + +2. By default, GDB doesn't always show the PC (and thus the PC flags) in +backtraces. +--- + gdb/aarch64-tdep.c | 37 ++++++++++++--------- + gdb/arch-utils.c | 8 +++++ + gdb/arch-utils.h | 3 ++ + gdb/gdbarch-gen.h | 6 ++++ + gdb/gdbarch.c | 22 ++++++++++++ + gdb/gdbarch_components.py | 11 ++++++ + gdb/stack.c | 8 +++++ + gdb/testsuite/gdb.arch/aarch64-gcs-core.exp | 4 +-- + gdb/testsuite/gdb.arch/aarch64-gcs.c | 31 ++++++++++++++--- + gdb/testsuite/gdb.arch/aarch64-gcs.exp | 21 +++++++----- + 10 files changed, 120 insertions(+), 31 deletions(-) + +diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c +index 4fd545e7efa..85865a74e85 100644 +--- a/gdb/aarch64-tdep.c ++++ b/gdb/aarch64-tdep.c +@@ -301,8 +301,8 @@ aarch64_frame_unmask_lr (aarch64_gdbarch_tdep *tdep, + return addr; + } + +-static std::optional +-aarch64_get_gcs_flag (frame_info_ptr frame) ++static std::string ++aarch64_get_frame_flags (frame_info_ptr frame) + { + int frame_level = frame_relative_level (frame); + if (frame_level < 0) +@@ -327,9 +327,24 @@ aarch64_get_gcs_flag (frame_info_ptr frame) + if (regcache->cooked_read (tdep->gcs_reg_base, &gcspr) != REG_VALID) + return {}; + ++ int real_frame_level = frame_level; ++ if (frame_level != 0) ++ { ++ /* Find out how many real frames there are between frame 0 and the current ++ one. */ ++ frame_info_ptr frame0 = frame; ++ while (frame_relative_level (frame0) > 0) ++ frame0 = get_next_frame (frame0); ++ ++ for (frame_info_ptr f = frame0; frame_relative_level (f) < frame_level; ++ f = get_prev_frame (f)) ++ if (get_frame_id (f).artificial_depth > 0) ++ real_frame_level--; ++ } ++ + gdb_byte buf[8]; + /* Read the GCS return address entry corresponding to this stack frame. */ +- if (target_read_memory (gcspr + 8 * frame_level, buf, sizeof (buf)) != 0) ++ if (target_read_memory (gcspr + 8 * real_frame_level, buf, sizeof (buf)) != 0) + return {}; + + bfd_endian byte_order = gdbarch_byte_order (regcache->arch ()); +@@ -349,21 +364,10 @@ aarch64_get_gcs_flag (frame_info_ptr frame) + static std::string + aarch64_get_pc_address_flags (const frame_info_ptr &frame, CORE_ADDR pc) + { +- std::string ret; +- + if (pc != 0 && get_frame_pc_masked (frame)) +- ret += "PAC"; ++ return "PAC"; + +- std::optional gcs_flag = aarch64_get_gcs_flag (frame); +- if (gcs_flag.has_value ()) +- { +- if (!ret.empty()) +- ret += " "; +- +- ret += *gcs_flag; +- } +- +- return ret; ++ return ""; + } + + /* Analyze a prologue, looking for a recognizable stack frame +@@ -4647,6 +4651,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) + set_gdbarch_gen_return_address (gdbarch, aarch64_gen_return_address); + + set_gdbarch_get_pc_address_flags (gdbarch, aarch64_get_pc_address_flags); ++ set_gdbarch_get_frame_flags (gdbarch, aarch64_get_frame_flags); + + tdesc_use_registers (gdbarch, tdesc, std::move (tdesc_data)); + +diff --git a/gdb/arch-utils.c b/gdb/arch-utils.c +index 83e29470bf7..058ab52b069 100644 +--- a/gdb/arch-utils.c ++++ b/gdb/arch-utils.c +@@ -1084,6 +1084,14 @@ default_get_pc_address_flags (const frame_info_ptr &frame, CORE_ADDR pc) + return ""; + } + ++/* See arch-utils.h. */ ++ ++std::string ++default_get_frame_flags (frame_info_ptr frame) ++{ ++ return {}; ++} ++ + /* See arch-utils.h. */ + void + default_read_core_file_mappings +diff --git a/gdb/arch-utils.h b/gdb/arch-utils.h +index 40c62f30a65..2b51ad3fadf 100644 +--- a/gdb/arch-utils.h ++++ b/gdb/arch-utils.h +@@ -298,6 +298,9 @@ extern ULONGEST default_type_align (struct gdbarch *gdbarch, + extern std::string default_get_pc_address_flags (const frame_info_ptr &frame, + CORE_ADDR pc); + ++/* Default implementation of gdbarch get_frame_flags method. */ ++extern std::string default_get_frame_flags (frame_info_ptr frame); ++ + /* Default implementation of gdbarch read_core_file_mappings method. */ + extern void default_read_core_file_mappings + (struct gdbarch *gdbarch, +diff --git a/gdb/gdbarch-gen.h b/gdb/gdbarch-gen.h +index b982fd7cd09..ba16d4c5f65 100644 +--- a/gdb/gdbarch-gen.h ++++ b/gdb/gdbarch-gen.h +@@ -1736,6 +1736,12 @@ typedef std::string (gdbarch_get_pc_address_flags_ftype) (const frame_info_ptr & + extern std::string gdbarch_get_pc_address_flags (struct gdbarch *gdbarch, const frame_info_ptr &frame, CORE_ADDR pc); + extern void set_gdbarch_get_pc_address_flags (struct gdbarch *gdbarch, gdbarch_get_pc_address_flags_ftype *get_pc_address_flags); + ++/* Return a string containing any flags for the given FRAME. */ ++ ++typedef std::string (gdbarch_get_frame_flags_ftype) (frame_info_ptr frame); ++extern std::string gdbarch_get_frame_flags (struct gdbarch *gdbarch, frame_info_ptr frame); ++extern void set_gdbarch_get_frame_flags (struct gdbarch *gdbarch, gdbarch_get_frame_flags_ftype *get_frame_flags); ++ + /* Read core file mappings */ + + typedef void (gdbarch_read_core_file_mappings_ftype) (struct gdbarch *gdbarch, struct bfd *cbfd, read_core_file_mappings_pre_loop_ftype pre_loop_cb, read_core_file_mappings_loop_ftype loop_cb); +diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c +index 58e9ebbdc59..4975ee9f028 100644 +--- a/gdb/gdbarch.c ++++ b/gdb/gdbarch.c +@@ -256,6 +256,7 @@ struct gdbarch + const disasm_options_and_args_t * valid_disassembler_options = 0; + gdbarch_type_align_ftype *type_align = default_type_align; + gdbarch_get_pc_address_flags_ftype *get_pc_address_flags = default_get_pc_address_flags; ++ gdbarch_get_frame_flags_ftype *get_frame_flags = default_get_frame_flags; + gdbarch_read_core_file_mappings_ftype *read_core_file_mappings = default_read_core_file_mappings; + gdbarch_use_target_description_from_corefile_notes_ftype *use_target_description_from_corefile_notes = default_use_target_description_from_corefile_notes; + }; +@@ -525,6 +526,7 @@ verify_gdbarch (struct gdbarch *gdbarch) + /* Skip verify of valid_disassembler_options, invalid_p == 0 */ + /* Skip verify of type_align, invalid_p == 0 */ + /* Skip verify of get_pc_address_flags, invalid_p == 0 */ ++ /* Skip verify of get_frame_flags, invalid_p == 0 */ + /* Skip verify of read_core_file_mappings, invalid_p == 0 */ + /* Skip verify of use_target_description_from_corefile_notes, invalid_p == 0 */ + if (!log.empty ()) +@@ -1380,6 +1382,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) + gdb_printf (file, + "gdbarch_dump: get_pc_address_flags = <%s>\n", + host_address_to_string (gdbarch->get_pc_address_flags)); ++ gdb_printf (file, ++ "gdbarch_dump: get_frame_flags = <%s>\n", ++ host_address_to_string (gdbarch->get_frame_flags)); + gdb_printf (file, + "gdbarch_dump: read_core_file_mappings = <%s>\n", + host_address_to_string (gdbarch->read_core_file_mappings)); +@@ -5430,6 +5435,23 @@ set_gdbarch_get_pc_address_flags (struct gdbarch *gdbarch, + gdbarch->get_pc_address_flags = get_pc_address_flags; + } + ++std::string ++gdbarch_get_frame_flags (struct gdbarch *gdbarch, frame_info_ptr frame) ++{ ++ gdb_assert (gdbarch != NULL); ++ gdb_assert (gdbarch->get_frame_flags != NULL); ++ if (gdbarch_debug >= 2) ++ gdb_printf (gdb_stdlog, "gdbarch_get_frame_flags called\n"); ++ return gdbarch->get_frame_flags (frame); ++} ++ ++void ++set_gdbarch_get_frame_flags (struct gdbarch *gdbarch, ++ gdbarch_get_frame_flags_ftype get_frame_flags) ++{ ++ gdbarch->get_frame_flags = get_frame_flags; ++} ++ + void + gdbarch_read_core_file_mappings (struct gdbarch *gdbarch, struct bfd *cbfd, read_core_file_mappings_pre_loop_ftype pre_loop_cb, read_core_file_mappings_loop_ftype loop_cb) + { +diff --git a/gdb/gdbarch_components.py b/gdb/gdbarch_components.py +index 4006380076d..9159de07b1c 100644 +--- a/gdb/gdbarch_components.py ++++ b/gdb/gdbarch_components.py +@@ -2749,6 +2749,17 @@ Return a string containing any flags for the given PC in the given FRAME. + invalid=False, + ) + ++Function( ++ comment=""" ++Return a string containing any flags for the given FRAME. ++""", ++ type="std::string", ++ name="get_frame_flags", ++ params=[("frame_info_ptr", "frame")], ++ predefault="default_get_frame_flags", ++ invalid=False, ++) ++ + Method( + comment=""" + Read core file mappings +diff --git a/gdb/stack.c b/gdb/stack.c +index b36193be2f3..b1e96c996fe 100644 +--- a/gdb/stack.c ++++ b/gdb/stack.c +@@ -1441,6 +1441,14 @@ print_frame (struct ui_out *uiout, + if (uiout->is_mi_like_p ()) + uiout->field_string ("arch", + (gdbarch_bfd_arch_info (gdbarch))->printable_name); ++ ++ std::string flags = gdbarch_get_frame_flags (gdbarch, frame); ++ if (!flags.empty ()) ++ { ++ uiout->text (" ["); ++ uiout->field_string ("frame_flags", flags); ++ uiout->text ("]"); ++ } + } + + uiout->text ("\n"); +diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs-core.exp b/gdb/testsuite/gdb.arch/aarch64-gcs-core.exp +index 73db3c1a87c..71b8d8b681b 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs-core.exp ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs-core.exp +@@ -38,7 +38,7 @@ gdb_test "continue" \ + "" \ + "Program received signal SIGSEGV, Segmentation fault" \ + "Guarded Control Stack error\\." \ +- "function \\(gcspr=$hex\\) at .*aarch64-gcs-core.c:$decimal" \ ++ "function \\(gcspr=$hex\\) at .*aarch64-gcs-core.c:$decimal \\\[GCS error\\\]" \ + {.*__asm__ volatile\("ret\\n"\);}] \ + "continue to SIGSEGV" + +@@ -68,7 +68,7 @@ proc check_core_file {core_filename saved_gcspr} { + "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" \ ++ "#0 function \\(gcspr=$hex\\) at .*aarch64-gcs-core.c:$decimal \\\[GCS error\\\]" \ + "$decimal.*__asm__ volatile\\(\"ret\\\\n\"\\);"] \ + "load core file"] { + untested "failed to load core file" +diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs.c b/gdb/testsuite/gdb.arch/aarch64-gcs.c +index 9cba9fa63bc..f9e40fe18e5 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs.c ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs.c +@@ -73,7 +73,7 @@ handler (int sig) + /* 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) ++normal_function2 (void) + { + /* x30 holds the return address. */ + register unsigned long x30 __asm__("x30") __attribute__ ((unused)); +@@ -83,6 +83,29 @@ function (unsigned long *gcspr) + __asm__ volatile("ret\n"); + } + ++static inline void __attribute__ ((__always_inline__)) ++inline_function2 (void) ++{ ++ normal_function2 (); ++} ++ ++/* Corrupt the return address to see if GDB will report a GCS error in this ++ function's frame . */ ++static void __attribute__ ((noinline)) ++normal_function1 (void) ++{ ++ /* x30 holds the return address. */ ++ register unsigned long x30 __asm__ ("x30") __attribute__ ((unused)); ++ x30 = 0xbadc0ffee; ++ inline_function2 (); ++} ++ ++static inline void __attribute__ ((__always_inline__)) ++inline_function1 (void) ++{ ++ normal_function1 (); ++} ++ + int + main (void) + { +@@ -114,7 +137,8 @@ main (void) + } + } + +- unsigned long *gcspr = get_gcspr (); ++ /* This is used by GDB. */ ++ __attribute__((unused)) unsigned long *gcspr = get_gcspr (); + + struct sigaction act = { 0 }; + +@@ -127,8 +151,7 @@ main (void) + + raise (SIGUSR1); + +- /* Pass gscpr to function just so it's used for something. */ +- function (gcspr); ++ 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 +index fed1f28ad85..d2b1185f73c 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs.exp ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs.exp +@@ -46,8 +46,7 @@ gdb_test_no_output "set \$gcspr_in_handler = \$gcspr" \ + "Save GCSPR value in handler for later" + # Select the frame above the frame, which makes GDB + # unwind the GCSPR from the signal frame GCS context. +-gdb_test "frame 2" \ +- "#2 ($hex in )?\\S+ \\(.*\\) (at|from) \\S+(\r\n(warning:.*: No such file or directory|\[0-9\]+\\s+in \\S+))?" \ ++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" \ +@@ -59,17 +58,21 @@ gdb_test "continue" \ + "" \ + "Program received signal SIGSEGV, Segmentation fault" \ + "Guarded Control Stack error\\." \ +- {.*__asm__ volatile\("ret\\n"\);}] \ ++ "normal_function2 \\(\\) at .*aarch64-gcs.c:$decimal \\\[GCS error\\\]" \ ++ "${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. +-gdb_test "print \$gcspr == \$gcspr_in_main - 8" ". = 1" \ ++# 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" + +-gdb_test "backtrace -frame-info location-and-address" \ ++gdb_test "backtrace" \ + [multi_line \ +- "#0 $hex \\\[GCS error\\\] in function \\(gcspr=$hex\\) at .*aarch64-gcs.c:$decimal" \ +- "#1 $hex \\\[GCS error\\\] in main \\(\\) at .*aarch64-gcs.c:$decimal"] \ +- "GCS flag in backtrace" ++ "#0 normal_function2 \\(\\) at .*aarch64-gcs.c:$decimal \\\[GCS error\\\]" \ ++ "#1 $hex in inline_function2 \\(\\) at .*aarch64-gcs.c:${decimal}" \ ++ "#2 normal_function1 \\(\\) at .*aarch64-gcs.c:$decimal \\\[GCS error\\\]" \ ++ "#3 $hex in inline_function1 \\(\\) at .*aarch64-gcs.c:${decimal}" \ ++ "#4 main \\(\\) at .*aarch64-gcs.c:${decimal}(?: \\\[GCS error\\\])?"] \ ++ "GCS flags in backtrace" +-- +2.25.1 + + +From 8953a001cf3ffcafa98ed9c3eda252dd86185623 Mon Sep 17 00:00:00 2001 +From: Thiago Jung Bauermann +Date: Fri, 8 Mar 2024 12:37:37 -0300 +Subject: [PATCH 20/27] Only install gdbarch_get_frame_flags hook if target + supports GCS. + +--- + gdb/aarch64-tdep.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c +index 85865a74e85..320388b78f8 100644 +--- a/gdb/aarch64-tdep.c ++++ b/gdb/aarch64-tdep.c +@@ -4651,7 +4651,8 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) + set_gdbarch_gen_return_address (gdbarch, aarch64_gen_return_address); + + set_gdbarch_get_pc_address_flags (gdbarch, aarch64_get_pc_address_flags); +- set_gdbarch_get_frame_flags (gdbarch, aarch64_get_frame_flags); ++ if (tdep->has_gcs ()) ++ set_gdbarch_get_frame_flags (gdbarch, aarch64_get_frame_flags); + + tdesc_use_registers (gdbarch, tdesc, std::move (tdesc_data)); + +-- +2.25.1 + + +From c3c70732d717ae01ea09b3cc4b86c16282fc9f77 Mon Sep 17 00:00:00 2001 +From: Thiago Jung Bauermann +Date: Wed, 6 Mar 2024 23:44:19 -0300 +Subject: [PATCH 21/27] Add testcase exercising GCS with displaced stepping + +It puts the breakpoint on the bl instruction to force GDB to copy +it to the displaced stepping buffer. +--- + .../gdb.arch/aarch64-gcs-disp-step.c | 108 ++++++++++++++++++ + .../gdb.arch/aarch64-gcs-disp-step.exp | 62 ++++++++++ + 2 files changed, 170 insertions(+) + create mode 100644 gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.c + create mode 100644 gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.exp + +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 00000000000..7f0e8888cae +--- /dev/null ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.c +@@ -0,0 +1,108 @@ ++/* This test program 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 . */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* Feature check for Guarded Control Stack. */ ++#ifndef HWCAP2_GCS ++#define HWCAP2_GCS (1UL << 48) ++#endif ++ ++#ifndef PR_GET_SHADOW_STACK_STATUS ++#define PR_GET_SHADOW_STACK_STATUS 71 ++#define PR_SET_SHADOW_STACK_STATUS 72 ++#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; \ ++ \ ++ asm volatile("mrs %0, S3_3_C2_C5_1" : "=r"(gcspr) : : "cc"); \ ++ \ ++ gcspr; \ ++ }) ++ ++static int __attribute__ ((noinline)) ++function (void) ++{ ++ return EXIT_SUCCESS; ++} ++ ++int ++main (void) ++{ ++ if (!(getauxval (AT_HWCAP2) & HWCAP2_GCS)) ++ 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; ++ } ++ } ++ ++ /* This is used by GDB. */ ++ __attribute__((unused)) unsigned long *gcspr = get_gcspr (); ++ ++ ret = function (); ++ ++ /* Avoid returning, in case libc doesn't understand GCS. */ ++ exit (ret); ++} +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 00000000000..51ca1eeef38 +--- /dev/null ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.exp +@@ -0,0 +1,62 @@ ++# 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 . ++ ++# 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 -1 ++} ++ ++if ![runto_main] { ++ return ++} ++ ++gdb_test_no_output "set breakpoint auto-hw off" ++gdb_test_no_output "set displaced-stepping on" ++ ++# Get the address of function's return instruction. ++set addr_bl 0 ++set test "Get address of bl instruction" ++gdb_test_multiple "disassemble main" $test -lbl { ++ -re "\r\n\\s+($hex) <\\+${decimal}>:\\s+bl\\s+${hex} (?=\r\n)" { ++ set addr_bl $expect_out(1,string) ++ exp_continue ++ } ++ -re "$::gdb_prompt \$" { ++ gdb_assert { $addr_bl != 0 } $test ++ } ++} ++ ++gdb_test "break *$addr_bl" \ ++ "Breakpoint $decimal at $hex: file .*aarch64-gcs-disp-step.c, line ${decimal}." \ ++ "Set breakpoint at bl instruction" ++ ++gdb_test "continue" \ ++ [multi_line \ ++ "Continuing\\." \ ++ "" \ ++ "Breakpoint $decimal, main \\(\\) at .*aarch64-gcs-disp-step.c:${decimal}(?: \\\[GCS error\\\])?" \ ++ "${decimal}\\s+ret = function \\(\\);"] \ ++ "continue to breakpoint" ++ ++gdb_test "continue" \ ++ [multi_line \ ++ "Continuing\\." \ ++ "\\\[Inferior 1 \\(process $decimal\\) exited normally\\\]"] \ ++ "Continue past breakpoint" +-- +2.25.1 + + +From aa6e271fcb021d6054c1f271674ea8bf367c6c74 Mon Sep 17 00:00:00 2001 +From: Thiago Jung Bauermann +Date: Fri, 8 Mar 2024 20:13:53 -0300 +Subject: [PATCH 22/27] Implement GCS support in displaced stepping for bl + instruction + +The following branch with link instructions still need to be supported: + +- BLR +- BLRAA +- BLRAAZ +- BLRAB +- BLRABZ +--- + gdb/aarch64-tdep.c | 63 ++++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 58 insertions(+), 5 deletions(-) + +diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c +index 320388b78f8..765c6072836 100644 +--- a/gdb/aarch64-tdep.c ++++ b/gdb/aarch64-tdep.c +@@ -3620,6 +3620,9 @@ struct aarch64_displaced_step_copy_insn_closure + /* PC adjustment offset after displaced stepping. If 0, then we don't + write the PC back, assuming the PC is already the right address. */ + int32_t pc_adjust = 0; ++ ++ /* True if it's a branch instruction that saves the link register. */ ++ bool linked_branch = false; + }; + + /* Data when visiting instructions for displaced stepping. */ +@@ -3640,6 +3643,47 @@ struct aarch64_displaced_step_data + aarch64_displaced_step_copy_insn_closure *dsc; + }; + ++/* If push is true, push lr_value to the Guarded Control Stack. ++ Otherwise, remove newest entry from the Guarded Control Stack. */ ++ ++static void ++aarch64_push_gcs_entry (regcache *regs, CORE_ADDR lr_value) ++{ ++ gdbarch *arch = regs->arch (); ++ aarch64_gdbarch_tdep *tdep = gdbarch_tdep (arch); ++ CORE_ADDR gcs_addr; ++ ++ enum register_status status = regs->cooked_read (tdep->gcs_reg_base, ++ &gcs_addr); ++ if (status != REG_VALID) ++ error ("Can't read $gcspr."); ++ ++ gcs_addr -= 8; ++ gdb_byte buf[8]; ++ store_integer (buf, gdbarch_byte_order (arch), lr_value); ++ if (target_write_memory (gcs_addr, buf, sizeof (buf)) != 0) ++ error ("Can't write to Guarded Control Stack."); ++ ++ /* Update GCSPR. */ ++ regcache_cooked_write_unsigned (regs, tdep->gcs_reg_base, gcs_addr); ++} ++ ++static void ++aarch64_pop_gcs_entry (regcache *regs) ++{ ++ gdbarch *arch = regs->arch (); ++ aarch64_gdbarch_tdep *tdep = gdbarch_tdep (arch); ++ CORE_ADDR gcs_addr; ++ ++ enum register_status status = regs->cooked_read (tdep->gcs_reg_base, ++ &gcs_addr); ++ if (status != REG_VALID) ++ error ("Can't read $gcspr."); ++ ++ /* Update GCSPR. */ ++ regcache_cooked_write_unsigned (regs, tdep->gcs_reg_base, gcs_addr + 8); ++} ++ + /* Implementation of aarch64_insn_visitor method "b". */ + + static void +@@ -3671,6 +3715,11 @@ aarch64_displaced_step_b (const int is_bl, const int32_t offset, + /* Update LR. */ + regcache_cooked_write_unsigned (dsd->regs, AARCH64_LR_REGNUM, + data->insn_addr + 4); ++ dsd->dsc->linked_branch = true; ++ aarch64_gdbarch_tdep *tdep ++ = gdbarch_tdep (dsd->regs->arch ()); ++ if (tdep->has_gcs ()) ++ aarch64_push_gcs_entry (dsd->regs, data->insn_addr + 4); + } + } + +@@ -3925,20 +3974,24 @@ aarch64_displaced_step_fixup (struct gdbarch *gdbarch, + CORE_ADDR from, CORE_ADDR to, + struct regcache *regs, bool completed_p) + { ++ aarch64_displaced_step_copy_insn_closure *dsc ++ = (aarch64_displaced_step_copy_insn_closure *) dsc_; + CORE_ADDR pc = regcache_read_pc (regs); + +- /* If the displaced instruction didn't complete successfully then all we +- need to do is restore the program counter. */ ++ /* If the displaced instruction didn't complete successfully then we need ++ to restore the program counter, and perhaps the Guarded Control Stack. */ + if (!completed_p) + { ++ aarch64_gdbarch_tdep *tdep ++ = gdbarch_tdep (gdbarch); ++ if (dsc->linked_branch && tdep->has_gcs ()) ++ aarch64_pop_gcs_entry (regs); ++ + pc = from + (pc - to); + regcache_write_pc (regs, pc); + return; + } + +- aarch64_displaced_step_copy_insn_closure *dsc +- = (aarch64_displaced_step_copy_insn_closure *) dsc_; +- + displaced_debug_printf ("PC after stepping: %s (was %s).", + paddress (gdbarch, pc), paddress (gdbarch, to)); + +-- +2.25.1 + + +From 9ed7cf0cfdeaaf02843decdc6f0b7b2b231acc6f Mon Sep 17 00:00:00 2001 +From: Thiago Jung Bauermann +Date: Wed, 13 Mar 2024 00:02:05 -0300 +Subject: [PATCH 23/27] Implement GCS support in displaced stepping for blr + instruction + +The following branch with link instructions with pointer authentication +still need to be supported: + +- BLRAA +- BLRAAZ +- BLRAB +- BLRABZ + +They are left for later because GDB doesn't have support for displaced +stepping with those instructions, so that would have to be done first. +--- + gdb/aarch64-tdep.c | 5 ++++ + .../gdb.arch/aarch64-gcs-disp-step.c | 6 +++++ + .../gdb.arch/aarch64-gcs-disp-step.exp | 27 +++++++++++++++---- + 3 files changed, 33 insertions(+), 5 deletions(-) + +diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c +index 765c6072836..11371f98ad2 100644 +--- a/gdb/aarch64-tdep.c ++++ b/gdb/aarch64-tdep.c +@@ -3878,6 +3878,11 @@ aarch64_displaced_step_others (const uint32_t insn, + aarch64_emit_insn (dsd->insn_buf, insn & 0xffdfffff); + regcache_cooked_write_unsigned (dsd->regs, AARCH64_LR_REGNUM, + data->insn_addr + 4); ++ dsd->dsc->linked_branch = true; ++ aarch64_gdbarch_tdep *tdep ++ = gdbarch_tdep (dsd->regs->arch ()); ++ if (tdep->has_gcs ()) ++ aarch64_push_gcs_entry (dsd->regs, data->insn_addr + 4); + } + else + aarch64_emit_insn (dsd->insn_buf, insn); +diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.c b/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.c +index 7f0e8888cae..6abcf05070b 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.c ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.c +@@ -103,6 +103,12 @@ main (void) + + ret = function (); + ++ register long x0 __asm__("x0"); ++ __asm__ ("blr %1" ++ : "=r"(x0) ++ : "r"(&function) ++ : "x30"); ++ + /* Avoid returning, in case libc doesn't understand GCS. */ + exit (ret); + } +diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.exp b/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.exp +index 51ca1eeef38..a8a8d8a15e9 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.exp ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.exp +@@ -30,16 +30,21 @@ if ![runto_main] { + gdb_test_no_output "set breakpoint auto-hw off" + gdb_test_no_output "set displaced-stepping on" + +-# Get the address of function's return instruction. ++# Get the address of branch and link instructions of interest in main. + set addr_bl 0 +-set test "Get address of bl instruction" ++set addr_blr 0 ++set test "Get address of branch and link instructions" + gdb_test_multiple "disassemble main" $test -lbl { + -re "\r\n\\s+($hex) <\\+${decimal}>:\\s+bl\\s+${hex} (?=\r\n)" { + set addr_bl $expect_out(1,string) + exp_continue + } ++ -re "\r\n\\s+($hex) <\\+${decimal}>:\\s+blr\\s+x${decimal}(?=\r\n)" { ++ set addr_blr $expect_out(1,string) ++ exp_continue ++ } + -re "$::gdb_prompt \$" { +- gdb_assert { $addr_bl != 0 } $test ++ gdb_assert { $addr_bl != 0 && $addr_blr != 0 } $test + } + } + +@@ -47,16 +52,28 @@ 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, main \\(\\) at .*aarch64-gcs-disp-step.c:${decimal}(?: \\\[GCS error\\\])?" \ + "${decimal}\\s+ret = function \\(\\);"] \ +- "continue to breakpoint" ++ "continue to breakpoint at bl" ++ ++gdb_test "continue" \ ++ [multi_line \ ++ "Continuing\\." \ ++ "" \ ++ "Breakpoint $decimal, $hex in main \\(\\) at .*aarch64-gcs-disp-step.c:${decimal}(?: \\\[GCS error\\\])?" \ ++ "${decimal}\\s+__asm__ \\(\"blr %1\""] \ ++ "continue to breakpoint at blr" + + gdb_test "continue" \ + [multi_line \ + "Continuing\\." \ + "\\\[Inferior 1 \\(process $decimal\\) exited normally\\\]"] \ +- "Continue past breakpoint" ++ "Continue until inferior exits" +-- +2.25.1 + + +From e443f8c2a14a712209e6f56dcfdd274d2699173c Mon Sep 17 00:00:00 2001 +From: Thiago Jung Bauermann +Date: Wed, 13 Mar 2024 14:47:44 -0300 +Subject: [PATCH 24/27] Adjust case of test names to convention + +The GDB Testcase Cookbook says that "Test names should start with a +lower case", so adjust accordingly. + +Also take the opportunity to use lowercase for gcspr. +--- + .../gdb.arch/aarch64-gcs-disp-step.exp | 8 +++---- + gdb/testsuite/gdb.arch/aarch64-gcs.exp | 22 +++++++++---------- + 2 files changed, 15 insertions(+), 15 deletions(-) + +diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.exp b/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.exp +index a8a8d8a15e9..117fed52ef3 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.exp ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.exp +@@ -33,7 +33,7 @@ gdb_test_no_output "set displaced-stepping on" + # Get the address of branch and link instructions of interest in main. + set addr_bl 0 + set addr_blr 0 +-set test "Get address of branch and link instructions" ++set test "get address of branch and link instructions" + gdb_test_multiple "disassemble main" $test -lbl { + -re "\r\n\\s+($hex) <\\+${decimal}>:\\s+bl\\s+${hex} (?=\r\n)" { + set addr_bl $expect_out(1,string) +@@ -50,11 +50,11 @@ gdb_test_multiple "disassemble main" $test -lbl { + + gdb_test "break *$addr_bl" \ + "Breakpoint $decimal at $hex: file .*aarch64-gcs-disp-step.c, line ${decimal}." \ +- "Set breakpoint at bl instruction" ++ "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" ++ "set breakpoint at blr instruction" + + gdb_test "continue" \ + [multi_line \ +@@ -76,4 +76,4 @@ gdb_test "continue" \ + [multi_line \ + "Continuing\\." \ + "\\\[Inferior 1 \\(process $decimal\\) exited normally\\\]"] \ +- "Continue until inferior exits" ++ "continue until inferior exits" +diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs.exp b/gdb/testsuite/gdb.arch/aarch64-gcs.exp +index d2b1185f73c..7bf7b6f0c98 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs.exp ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs.exp +@@ -29,28 +29,28 @@ if ![runto ${linespec}] { + return + } + +-gdb_test "print \$gcspr" ". = \\(void \\*\\) $hex" "GDB knows about GCSPR" +-gdb_test "print \$gcspr == gcspr" ". = 1" "GDB has the correct GCSPR value" ++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" ++ "save gcspr value in main for later" + + 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" ++ "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" ++ "save gcspr value in handler for later" + # Select the frame above the frame, which makes GDB +-# unwind the GCSPR from the signal frame GCS context. ++# 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" ++ "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" ++ "gcspr unwound from signal context is correct" + + gdb_test "continue" \ + [multi_line \ +@@ -63,10 +63,10 @@ gdb_test "continue" \ + "continue to SIGSEGV" + + gdb_test "print \$_siginfo.si_code" ". = 10" \ +- "Test value of si_code when GCS SIGSEGV happens" ++ "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 value of gcspr when GCS SIGSEGV happens" + + gdb_test "backtrace" \ + [multi_line \ +-- +2.25.1 + + +From 04820067592392fc316d38841629289b509e8475 Mon Sep 17 00:00:00 2001 +From: Thiago Jung Bauermann +Date: Wed, 13 Mar 2024 23:45:23 -0300 +Subject: [PATCH 25/27] Move aarch64_push_entry and aarch64_pop_entry up in the + file + +The former will be used in aarch64_push_dummy_call, so moving up avoids +the need to add a function prototype. + +There's no code change. +--- + gdb/aarch64-tdep.c | 82 +++++++++++++------------- + gdb/testsuite/gdb.arch/aarch64-gcs.c | 6 ++ + gdb/testsuite/gdb.arch/aarch64-gcs.exp | 5 ++ + 3 files changed, 52 insertions(+), 41 deletions(-) + +diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c +index 11371f98ad2..02ce2eb5189 100644 +--- a/gdb/aarch64-tdep.c ++++ b/gdb/aarch64-tdep.c +@@ -1939,6 +1939,47 @@ pass_in_v_vfp_candidate (struct gdbarch *gdbarch, struct regcache *regcache, + } + } + ++/* If push is true, push lr_value to the Guarded Control Stack. ++ Otherwise, remove newest entry from the Guarded Control Stack. */ ++ ++static void ++aarch64_push_gcs_entry (regcache *regs, CORE_ADDR lr_value) ++{ ++ gdbarch *arch = regs->arch (); ++ aarch64_gdbarch_tdep *tdep = gdbarch_tdep (arch); ++ CORE_ADDR gcs_addr; ++ ++ enum register_status status = regs->cooked_read (tdep->gcs_reg_base, ++ &gcs_addr); ++ if (status != REG_VALID) ++ error ("Can't read $gcspr."); ++ ++ gcs_addr -= 8; ++ gdb_byte buf[8]; ++ store_integer (buf, gdbarch_byte_order (arch), lr_value); ++ if (target_write_memory (gcs_addr, buf, sizeof (buf)) != 0) ++ error ("Can't write to Guarded Control Stack."); ++ ++ /* Update GCSPR. */ ++ regcache_cooked_write_unsigned (regs, tdep->gcs_reg_base, gcs_addr); ++} ++ ++static void ++aarch64_pop_gcs_entry (regcache *regs) ++{ ++ gdbarch *arch = regs->arch (); ++ aarch64_gdbarch_tdep *tdep = gdbarch_tdep (arch); ++ CORE_ADDR gcs_addr; ++ ++ enum register_status status = regs->cooked_read (tdep->gcs_reg_base, ++ &gcs_addr); ++ if (status != REG_VALID) ++ error ("Can't read $gcspr."); ++ ++ /* Update GCSPR. */ ++ regcache_cooked_write_unsigned (regs, tdep->gcs_reg_base, gcs_addr + 8); ++} ++ + /* Implement the "push_dummy_call" gdbarch method. */ + + static CORE_ADDR +@@ -3643,47 +3684,6 @@ struct aarch64_displaced_step_data + aarch64_displaced_step_copy_insn_closure *dsc; + }; + +-/* If push is true, push lr_value to the Guarded Control Stack. +- Otherwise, remove newest entry from the Guarded Control Stack. */ +- +-static void +-aarch64_push_gcs_entry (regcache *regs, CORE_ADDR lr_value) +-{ +- gdbarch *arch = regs->arch (); +- aarch64_gdbarch_tdep *tdep = gdbarch_tdep (arch); +- CORE_ADDR gcs_addr; +- +- enum register_status status = regs->cooked_read (tdep->gcs_reg_base, +- &gcs_addr); +- if (status != REG_VALID) +- error ("Can't read $gcspr."); +- +- gcs_addr -= 8; +- gdb_byte buf[8]; +- store_integer (buf, gdbarch_byte_order (arch), lr_value); +- if (target_write_memory (gcs_addr, buf, sizeof (buf)) != 0) +- error ("Can't write to Guarded Control Stack."); +- +- /* Update GCSPR. */ +- regcache_cooked_write_unsigned (regs, tdep->gcs_reg_base, gcs_addr); +-} +- +-static void +-aarch64_pop_gcs_entry (regcache *regs) +-{ +- gdbarch *arch = regs->arch (); +- aarch64_gdbarch_tdep *tdep = gdbarch_tdep (arch); +- CORE_ADDR gcs_addr; +- +- enum register_status status = regs->cooked_read (tdep->gcs_reg_base, +- &gcs_addr); +- if (status != REG_VALID) +- error ("Can't read $gcspr."); +- +- /* Update GCSPR. */ +- regcache_cooked_write_unsigned (regs, tdep->gcs_reg_base, gcs_addr + 8); +-} +- + /* Implementation of aarch64_insn_visitor method "b". */ + + static void +diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs.c b/gdb/testsuite/gdb.arch/aarch64-gcs.c +index f9e40fe18e5..84b1d6dc99c 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs.c ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs.c +@@ -70,6 +70,12 @@ 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)) +diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs.exp b/gdb/testsuite/gdb.arch/aarch64-gcs.exp +index 7bf7b6f0c98..c9dd4a1ec84 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs.exp ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs.exp +@@ -34,6 +34,11 @@ 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" \ +-- +2.25.1 + + +From 64d46d64e4fc099a0f2e152f250d16c709edab11 Mon Sep 17 00:00:00 2001 +From: Thiago Jung Bauermann +Date: Thu, 4 Jul 2024 00:45:04 -0300 +Subject: [PATCH 26/27] Print error message in testcases when GCS bit isn't + found in AT_HWCAP2. + +--- + gdb/testsuite/gdb.arch/aarch64-gcs-core.c | 5 ++++- + gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.c | 5 ++++- + gdb/testsuite/gdb.arch/aarch64-gcs.c | 5 ++++- + 3 files changed, 12 insertions(+), 3 deletions(-) + +diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs-core.c b/gdb/testsuite/gdb.arch/aarch64-gcs-core.c +index 7508f7b77fa..83c72875344 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs-core.c ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs-core.c +@@ -83,7 +83,10 @@ int + main (void) + { + if (!(getauxval (AT_HWCAP2) & HWCAP2_GCS)) +- return EXIT_FAILURE; ++ { ++ fprintf (stderr, "GCS support not found in AT_HWCAP2\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 +diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.c b/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.c +index 6abcf05070b..557fb3b0fdd 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.c ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.c +@@ -71,7 +71,10 @@ int + main (void) + { + if (!(getauxval (AT_HWCAP2) & HWCAP2_GCS)) +- return EXIT_FAILURE; ++ { ++ fprintf (stderr, "GCS support not found in AT_HWCAP2\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 +diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs.c b/gdb/testsuite/gdb.arch/aarch64-gcs.c +index 84b1d6dc99c..a87ee189096 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs.c ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs.c +@@ -116,7 +116,10 @@ int + main (void) + { + if (!(getauxval (AT_HWCAP2) & HWCAP2_GCS)) +- return EXIT_FAILURE; ++ { ++ fprintf (stderr, "GCS support not found in AT_HWCAP2\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 +-- +2.25.1 + + +From da6b6b916a0bf7fcf862253cb282e54edc41f6a6 Mon Sep 17 00:00:00 2001 +From: Thiago Jung Bauermann +Date: Thu, 4 Jul 2024 00:20:49 -0300 +Subject: [PATCH 27/27] Update ABI constant values to match Linux kernel GCS + patches v9 + +- HWCAP2_GCS +- NT_ARM_GCS +- PR_GET_SHADOW_STACK_STATUS +- PR_SET_SHADOW_STACK_STATUS +--- + gdb/arch/aarch64-gcs-linux.h | 2 +- + gdb/testsuite/gdb.arch/aarch64-gcs-core.c | 6 +++--- + gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.c | 6 +++--- + gdb/testsuite/gdb.arch/aarch64-gcs.c | 6 +++--- + include/elf/common.h | 2 +- + 5 files changed, 11 insertions(+), 11 deletions(-) + +diff --git a/gdb/arch/aarch64-gcs-linux.h b/gdb/arch/aarch64-gcs-linux.h +index 761c498b76a..29e9e558298 100644 +--- a/gdb/arch/aarch64-gcs-linux.h ++++ b/gdb/arch/aarch64-gcs-linux.h +@@ -24,7 +24,7 @@ + + /* Feature check for Guarded Control Stack. */ + #ifndef HWCAP2_GCS +-#define HWCAP2_GCS (1UL << 48) ++#define HWCAP2_GCS (1UL << 63) + #endif + + /* The GCS regset consists of a single 64-bit register. */ +diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs-core.c b/gdb/testsuite/gdb.arch/aarch64-gcs-core.c +index 83c72875344..27a451daa01 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs-core.c ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs-core.c +@@ -23,12 +23,12 @@ + + /* Feature check for Guarded Control Stack. */ + #ifndef HWCAP2_GCS +-#define HWCAP2_GCS (1UL << 48) ++#define HWCAP2_GCS (1UL << 63) + #endif + + #ifndef PR_GET_SHADOW_STACK_STATUS +-#define PR_GET_SHADOW_STACK_STATUS 71 +-#define PR_SET_SHADOW_STACK_STATUS 72 ++#define PR_GET_SHADOW_STACK_STATUS 74 ++#define PR_SET_SHADOW_STACK_STATUS 75 + #define PR_SHADOW_STACK_ENABLE (1UL << 0) + #endif + +diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.c b/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.c +index 557fb3b0fdd..3555ec1aa85 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.c ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.c +@@ -23,12 +23,12 @@ + + /* Feature check for Guarded Control Stack. */ + #ifndef HWCAP2_GCS +-#define HWCAP2_GCS (1UL << 48) ++#define HWCAP2_GCS (1UL << 63) + #endif + + #ifndef PR_GET_SHADOW_STACK_STATUS +-#define PR_GET_SHADOW_STACK_STATUS 71 +-#define PR_SET_SHADOW_STACK_STATUS 72 ++#define PR_GET_SHADOW_STACK_STATUS 74 ++#define PR_SET_SHADOW_STACK_STATUS 75 + #define PR_SHADOW_STACK_ENABLE (1UL << 0) + #endif + +diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs.c b/gdb/testsuite/gdb.arch/aarch64-gcs.c +index a87ee189096..a20dd1f8077 100644 +--- a/gdb/testsuite/gdb.arch/aarch64-gcs.c ++++ b/gdb/testsuite/gdb.arch/aarch64-gcs.c +@@ -24,12 +24,12 @@ + + /* Feature check for Guarded Control Stack. */ + #ifndef HWCAP2_GCS +-#define HWCAP2_GCS (1UL << 48) ++#define HWCAP2_GCS (1UL << 63) + #endif + + #ifndef PR_GET_SHADOW_STACK_STATUS +-#define PR_GET_SHADOW_STACK_STATUS 71 +-#define PR_SET_SHADOW_STACK_STATUS 72 ++#define PR_GET_SHADOW_STACK_STATUS 74 ++#define PR_SET_SHADOW_STACK_STATUS 75 + #define PR_SHADOW_STACK_ENABLE (1UL << 0) + #endif + +diff --git a/include/elf/common.h b/include/elf/common.h +index 09d11ae586b..54c66c9eff4 100644 +--- a/include/elf/common.h ++++ b/include/elf/common.h +@@ -739,7 +739,7 @@ + /* Note: name must be "LINUX". */ + #define NT_ARM_ZT 0x40d /* AArch64 SME2 ZT registers. */ + /* Note: name must be "LINUX". */ +-#define NT_ARM_GCS 0x40e /* AArch64 Guarded Control Stack ++#define NT_ARM_GCS 0x40f /* AArch64 Guarded Control Stack + registers. */ + /* Note name must be "LINUX". */ + #define NT_ARC_V2 0x600 /* ARC HS accumulator/extra registers. */ +-- +2.25.1 + diff --git a/meta-arm-gcs/recipes-devtools/gdb/gdb_15.1.bb b/meta-arm-gcs/recipes-devtools/gdb/gdb_15.1.bb new file mode 100644 index 00000000..5f155402 --- /dev/null +++ b/meta-arm-gcs/recipes-devtools/gdb/gdb_15.1.bb @@ -0,0 +1,40 @@ +require recipes-devtools/gdb/gdb-common.inc + +inherit gettext pkgconfig + +PACKAGES =+ "gdbserver" +FILES:gdbserver = "${bindir}/gdbserver" + +require recipes-devtools/gdb/gdb.inc + +FILESEXTRAPATHS:prepend := "${COREBASE}/meta/recipes-devtools/gdb/gdb:" + +# This patch doesn't apply to 15.1 +SRC_URI:remove = "file://0005-Change-order-of-CFLAGS.patch" +SRC_URI[sha256sum] = "38254eacd4572134bca9c5a5aa4d4ca564cbbd30c369d881f733fb6b903354f2" + +inherit python3-dir + +EXTRA_OEMAKE:append:libc-musl = "\ + gt_cv_func_gnugettext1_libc=yes \ + gt_cv_func_gnugettext2_libc=yes \ + gl_cv_func_working_strerror=yes \ + gl_cv_func_strerror_0_works=yes \ + gl_cv_func_gettimeofday_clobber=no \ + " + +do_configure:prepend() { + if [ "${@bb.utils.filter('PACKAGECONFIG', 'python', d)}" ]; then + cat > ${WORKDIR}/python << EOF +#!/bin/sh +case "\$2" in + --includes) echo "-I${STAGING_INCDIR}/${PYTHON_DIR}${PYTHON_ABI}/" ;; + --ldflags) echo "-Wl,-rpath-link,${STAGING_LIBDIR}/.. -Wl,-rpath,${libdir}/.. -lpthread -ldl -lutil -lm -lpython${PYTHON_BASEVERSION}${PYTHON_ABI}" ;; + --exec-prefix) echo "${exec_prefix}" ;; + *) exit 1 ;; +esac +exit 0 +EOF + chmod +x ${WORKDIR}/python + fi +} \ No newline at end of file diff --git a/meta-arm-gcs/recipes-devtools/gdb/gdb_15.1.bbappend b/meta-arm-gcs/recipes-devtools/gdb/gdb_15.1.bbappend new file mode 100644 index 00000000..ed5ecc21 --- /dev/null +++ b/meta-arm-gcs/recipes-devtools/gdb/gdb_15.1.bbappend @@ -0,0 +1,3 @@ +FILESEXTRAPATHS:prepend := "${THISDIR}/files:" + +SRC_URI += "file://gcs.patch" \ No newline at end of file