From patchwork Wed Jun 18 05:54:43 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thiago Jung Bauermann X-Patchwork-Id: 897541 Delivered-To: patch@linaro.org Received: by 2002:a5d:5f54:0:b0:3a4:ee3f:8f15 with SMTP id cm20csp135566wrb; Tue, 17 Jun 2025 22:59:16 -0700 (PDT) X-Forwarded-Encrypted: i=3; AJvYcCVdDEu8GuT5FZKUARRUsi8UR9PP1OM8w0XwkDRh1214Ji2uhxujvkoX+OKRhLZK4afWF8ovLA==@linaro.org X-Google-Smtp-Source: AGHT+IHEIZFxcEXPlrdpDLefY/SwNO1c/qIh+KxfmnhvF9xCmBMWwGTyjpjc86pdNWGGp89McVJi X-Received: by 2002:a05:620a:2795:b0:7d3:8df3:f5b1 with SMTP id af79cd13be357-7d3c6cf570dmr2480517385a.39.1750226356233; Tue, 17 Jun 2025 22:59:16 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1750226356; cv=pass; d=google.com; s=arc-20240605; b=gQA1sRLbOagofDfLa/sz0CXX0PKhO39AVG5LHwEh/7LtIbRX24PxuZOc1ieXGwbNBT 8W0PgpKjBYt0P85AnppRxbdF7B+AGXNdt+uI1SfxqdaMgnO+FTe5VRfiLyXp1ZtBAsy0 y98bkd/Ht5S0gDNMjpvHdmosO/BOZ9OpFHPMzTF7Wbfk7YyLGv4NzZaDqeE2U0EoE4Nw s7N2r3Dze1BiL1nrHUUiNMSWIcXsuAYiVm7tEdA++d1g9cAoDUEsr0I/d65eA/PkyQO3 mz3gOpWFddXJ/FSlb0x7wFAw74dNq/sFpe48b6qAzXZBVFtvbRG3t25DtA+jt/mRQaca NVlQ== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature:dkim-filter:arc-filter:dmarc-filter :delivered-to:dkim-filter; bh=LhJ2xVcbJ7uF0ZlLI8MauJ6Au62sj2wFfTPN6Ke3Pwo=; fh=v0Swrqm/HGzmFfs2Lyn4KGEK39u4NVWMm4qGXeDZh/s=; b=OTPBOPGTCVHUe+7FI1u6gyZxFg0EsdsUrry3ZNV5yHDE1Tz7sXiTDv+6WOCMYOquB8 eD1DTPqRoee9jzQZit9AiN6KTkXZH+ry4IsQRChvEw9+nw1jQNegMKgEFJrFIumh+FlY mSHYaEmG9T1XiJx7of0Ly/8jQ6BnwBXiSJTJxB/L15IEO3C1Ureb+3t+JgG03S6XS092 Mrd7BpFwCjQ5xW4i8CNdn0sooyb/zyF2+smNSMAD5wNs6joFyHUmJTb2bhwIv43qTiyr c6dji6YP5VeRxB+FBzGcliIU85kR5/5en1y+sKpjOYCnMVtcybnKHMeI+cxrliqwk47B Qi1A==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=Q2AYTv91; arc=pass (i=1); spf=pass (google.com: domain of gdb-patches-bounces~patch=linaro.org@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gdb-patches-bounces~patch=linaro.org@sourceware.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from server2.sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id af79cd13be357-7d3b8f3a55bsi1297378485a.554.2025.06.17.22.59.16 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 Jun 2025 22:59:16 -0700 (PDT) Received-SPF: pass (google.com: domain of gdb-patches-bounces~patch=linaro.org@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=Q2AYTv91; arc=pass (i=1); spf=pass (google.com: domain of gdb-patches-bounces~patch=linaro.org@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gdb-patches-bounces~patch=linaro.org@sourceware.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id C6CDE3816944 for ; Wed, 18 Jun 2025 05:59:15 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C6CDE3816944 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=linaro.org header.i=@linaro.org header.a=rsa-sha256 header.s=google header.b=Q2AYTv91 X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail-pj1-x102e.google.com (mail-pj1-x102e.google.com [IPv6:2607:f8b0:4864:20::102e]) by sourceware.org (Postfix) with ESMTPS id E36133816949 for ; Wed, 18 Jun 2025 05:55:11 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org E36133816949 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=linaro.org ARC-Filter: OpenARC Filter v1.0.0 sourceware.org E36133816949 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::102e ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1750226112; cv=none; b=VzXcERMc7/hBJVfcaq/4EpM6vNcgOkxPzK1UNqXliEZ6ISm3t0APPHtUnMK+/mbR6+uvUUeRUyKHbO+sQNW0gUFtlDEq44pHQ2jeQkWliYkIP5+EP5gLIkztBPP98XSifj82gBzq3L/7rZkNKOB/1xlCP49SQjVQxrm95MLrN8w= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1750226112; c=relaxed/simple; bh=54N2IPMM31s2EB6cPeWbxIAsG0izz/qzsiAexnDiyIU=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=jbFyxmC1rmf0vdNb6+WZ9WAtM2+Gn77aFw/yY67YaG/F0Lzxuw2Fh4DJ1zXLdIT/f4GM30X2WlXMuaPExSB5NAaBRexdeIIM+c0RP+AM1GEeBl4APQLFuHD86YS751hpbuoMKDw42XZ6McdINzE1EUY4Rs7VccgJqRAJRCQME4I= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E36133816949 Received: by mail-pj1-x102e.google.com with SMTP id 98e67ed59e1d1-313910f392dso5779410a91.2 for ; Tue, 17 Jun 2025 22:55:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1750226110; x=1750830910; darn=sourceware.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=LhJ2xVcbJ7uF0ZlLI8MauJ6Au62sj2wFfTPN6Ke3Pwo=; b=Q2AYTv91CBCnU+3eClz4oJz8GydJdNDS7ciXPUkveq87ygDI9oiZfMNpS1IfqQfvQD bnbibKHMTLy1l6Mk0Gmt+h8dsCEMqzJnvY0F+W9InDBF3I6Z8CWsxCDfhLsH3SvGyK/p 6dYVFgY3C/P8UgdcVeLRYiEXUA9fHRaGpKuUoAPK9Vwt23PYHYzyXNvnn+Lmrb3fSA9g ZLtElKW02nBNfM3B5YxE31u4mDvStUgJD1WhA5mpaw69yjokC0L8JDsFNnj6yIg02WBO HhgB5TqEwnXRJ4ffcGqrRKU6GOJTG/uo8KKrCfB7iycm6A6cy/Czz0yLcEjfnQ5vWJbf 7mBw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1750226110; x=1750830910; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=LhJ2xVcbJ7uF0ZlLI8MauJ6Au62sj2wFfTPN6Ke3Pwo=; b=JzlQqgIRgVK+hnOdAb5a+hOoel7b78TPCpCIZDGHe1DLlcBJq224FI+hkPU4mdOoC5 Y48ACN8M4LROOi4A61DHxXXdOizGFLFoq+JKz6sBF9019MxrSbrZAUgTd3nIyapmOvvI 67ljmSBXUGJT3vUxNDIyYAHzZLiUwBjbnU3UmRi4032fVhyA4fXQWMgI9muXkKnpxGVL lMgNM8VyPhSr4msJDXJGt546Eoo2opDyyGnpGLnjDjuQpnJ6YK+7Y64ZWNR3r/hWVMsM l96Xoi+YpfrlpLfU0wp8jYlNBL8L+1hm5M8uAIhXzBr7UOYY4gyQCdof/GmjQaVE3tmf R1qA== X-Gm-Message-State: AOJu0YyH1fF23D4zjzeikFpZAL6HHkVtlCwEUiIa6lju1IxOkuuY/umd rHW+lYaE0CgGLZDrN2yEeH0Z17hsQB6ijEkb8FDYYLVPi2P8ShpSGq38k1snfZANt7yMqepKZvd o1E08 X-Gm-Gg: ASbGnct5OeWIHK6yWdCIH1rRzGc2Uv5A5TlCa2ZDSfGIhocqdHlVSOdsKOdwP+j1GYn HxKpMYqH5sJwE+FHdDd9PyVkFA+RSuLbDspk5FxyGhpYGqV9qkAe8yaxGdnPapRJKE6nvwHy97a Komm4QzRzYFb7AasfV2Uy9JissM0k2xZJeOi64uUumz/Ptf+Am1VVHf2I/SUisCWrGq2nsavO6P yWGISftY/kx7XDADrX91Zrs31etHOOoKT3OJ2eywLjJcTRMmr59jHzYmwBLITgOtd91VS6fN1LI X1CWjEUjjIyDf5oHgg0ITIleznK1Eu+lUVsP/aLx/ecu6RId//be2vNsA9+qnmtzp5Xo X-Received: by 2002:a17:90b:4cce:b0:312:639:a058 with SMTP id 98e67ed59e1d1-313f1d96ee5mr24784865a91.27.1750226109543; Tue, 17 Jun 2025 22:55:09 -0700 (PDT) Received: from localhost ([2804:14d:7e39:88d6:ae12:97ab:a9:43c]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-313c1c5feebsm13283850a91.41.2025.06.17.22.55.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 17 Jun 2025 22:55:09 -0700 (PDT) From: Thiago Jung Bauermann To: gdb-patches@sourceware.org Cc: Eli Zaretskii , "Schimpe, Christina" , Luis Machado Subject: [PATCH v2 7/9] GDB: aarch64-linux: Implement GCS support in displaced stepping Date: Wed, 18 Jun 2025 02:54:43 -0300 Message-ID: <20250618055445.709416-8-thiago.bauermann@linaro.org> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250618055445.709416-1-thiago.bauermann@linaro.org> References: <20250618055445.709416-1-thiago.bauermann@linaro.org> MIME-Version: 1.0 X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patch=linaro.org@sourceware.org When doing displaced step on a branch and link instruction with the Guarded Control Stack enabled, it's necessary to manually push and pop the GCS entry for the function call since GDB writes a simple branch instruction rather than a branch and link instruction in the displaced step buffer. The testcase exercises GCS with displaced stepping by putting the breakpoint on the bl instruction to force GDB to copy it to the displaced stepping buffer. In this situation GDB needs to manually manage the Guarded Control Stack. --- gdb/aarch64-linux-tdep.c | 30 ++++ gdb/aarch64-tdep.c | 47 +++++- gdb/linux-tdep.h | 7 + .../gdb.arch/aarch64-gcs-disp-step.c | 140 ++++++++++++++++++ .../gdb.arch/aarch64-gcs-disp-step.exp | 90 +++++++++++ 5 files changed, 309 insertions(+), 5 deletions(-) create mode 100644 gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.c create mode 100644 gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.exp Changes since v1: - Use aarch64_gdbarch_tdep::has_gcs_linux in aarch64_linux_get_shadow_stack_pointer and aarch64_linux_init_abi instead of has_gcs. - Moved aarch64-gcs-disp-step.exp to this patch. diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c index 6bd9dfc47d81..63c6f6b76b92 100644 --- a/gdb/aarch64-linux-tdep.c +++ b/gdb/aarch64-linux-tdep.c @@ -2534,6 +2534,32 @@ aarch64_linux_tagged_address_p (struct gdbarch *gdbarch, CORE_ADDR address) return true; } +/* Implement the "get_shadow_stack_pointer" gdbarch method. */ + +static std::optional +aarch64_linux_get_shadow_stack_pointer (gdbarch *gdbarch, regcache *regcache, + bool &shadow_stack_enabled) +{ + aarch64_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + shadow_stack_enabled = false; + + if (!tdep->has_gcs_linux ()) + return {}; + + uint64_t features_enabled; + enum register_status status = regcache->cooked_read (tdep->gcs_linux_reg_base, + &features_enabled); + if (status != REG_VALID) + error (_("Can't read $gcs_features_enabled.")); + + CORE_ADDR gcspr; + status = regcache->cooked_read (tdep->gcs_reg_base, &gcspr); + if (status != REG_VALID) + error (_("Can't read $gcspr.")); + + shadow_stack_enabled = features_enabled & PR_SHADOW_STACK_ENABLE; + return gcspr; +} /* AArch64 Linux implementation of the report_signal_info gdbarch hook. Displays information about possible memory tag violations. */ @@ -3106,6 +3132,10 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) sections. */ set_gdbarch_use_target_description_from_corefile_notes (gdbarch, aarch64_use_target_description_from_corefile_notes); + + if (tdep->has_gcs_linux ()) + set_gdbarch_get_shadow_stack_pointer (gdbarch, + aarch64_linux_get_shadow_stack_pointer); } #if GDB_SELF_TEST diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c index 0e9e6644dd0a..e21c4a8e9ae1 100644 --- a/gdb/aarch64-tdep.c +++ b/gdb/aarch64-tdep.c @@ -1911,6 +1911,24 @@ aarch64_push_gcs_entry (regcache *regs, CORE_ADDR lr_value) regcache_cooked_write_unsigned (regs, tdep->gcs_reg_base, gcs_addr); } +/* Remove the newest entry from the Guarded Control Stack. */ + +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 "shadow_stack_push" gdbarch method. */ static void @@ -3602,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. */ @@ -3653,6 +3674,12 @@ 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; + bool gcs_is_enabled; + gdbarch_get_shadow_stack_pointer (dsd->regs->arch (), dsd->regs, + gcs_is_enabled); + if (gcs_is_enabled) + aarch64_push_gcs_entry (dsd->regs, data->insn_addr + 4); } } @@ -3811,6 +3838,12 @@ 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; + bool gcs_is_enabled; + gdbarch_get_shadow_stack_pointer (dsd->regs->arch (), dsd->regs, + gcs_is_enabled); + if (gcs_is_enabled) + aarch64_push_gcs_entry (dsd->regs, data->insn_addr + 4); } else aarch64_emit_insn (dsd->insn_buf, insn); @@ -3907,20 +3940,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) { + bool gcs_is_enabled; + gdbarch_get_shadow_stack_pointer (gdbarch, regs, gcs_is_enabled); + if (dsc->linked_branch && gcs_is_enabled) + 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)); diff --git a/gdb/linux-tdep.h b/gdb/linux-tdep.h index 0bee4b34845d..fd4d060412e5 100644 --- a/gdb/linux-tdep.h +++ b/gdb/linux-tdep.h @@ -30,6 +30,13 @@ struct regcache; #define SEGV_CPERR 10 /* Control protection error. */ #endif +/* Flag which enables shadow stack in PR_SET_SHADOW_STACK_STATUS prctl. */ +#ifndef PR_SHADOW_STACK_ENABLE +#define PR_SHADOW_STACK_ENABLE (1UL << 0) +#define PR_SHADOW_STACK_WRITE (1UL << 1) +#define PR_SHADOW_STACK_PUSH (1UL << 2) +#endif + /* Enum used to define the extra fields of the siginfo type used by an architecture. */ enum linux_siginfo_extra_field_values 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 000000000000..3d895350ae42 --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.c @@ -0,0 +1,140 @@ +/* This test program is part of GDB, the GNU debugger. + + Copyright 2025 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include +#include +#include +#include +#include + +/* Feature check for Guarded Control Stack. */ +#ifndef HWCAP_GCS +#define HWCAP_GCS (1UL << 32) +#endif + +#ifndef PR_GET_SHADOW_STACK_STATUS +#define PR_GET_SHADOW_STACK_STATUS 74 +#define PR_SET_SHADOW_STACK_STATUS 75 +#define PR_SHADOW_STACK_ENABLE (1UL << 0) +#endif + +/* We need to use a macro to call prctl because after GCS is enabled, it's not + possible to return from the function which enabled it. This is because the + return address of the calling function isn't on the GCS. */ +#define my_syscall2(num, arg1, arg2) \ + ({ \ + register long _num __asm__("x8") = (num); \ + register long _arg1 __asm__("x0") = (long)(arg1); \ + register long _arg2 __asm__("x1") = (long)(arg2); \ + register long _arg3 __asm__("x2") = 0; \ + register long _arg4 __asm__("x3") = 0; \ + register long _arg5 __asm__("x4") = 0; \ + \ + __asm__ volatile("svc #0\n" \ + : "=r"(_arg1) \ + : "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \ + "r"(_arg5), "r"(_num) \ + : "memory", "cc"); \ + _arg1; \ + }) + +#define get_gcspr(void) \ + ({ \ + unsigned long *gcspr; \ + \ + /* Get GCSPR_EL0. */ \ + asm volatile("mrs %0, S3_3_C2_C5_1" : "=r"(gcspr) : : "cc"); \ + \ + gcspr; \ + }) + +static int __attribute__ ((noinline)) +function2 (void) +{ + return EXIT_SUCCESS; +} + +/* Put branch and link instructions being tested into their own functions so + that the program returns one level up in the stack after the displaced + stepped instruction. This tests that GDB doesn't leave the GCS out of sync + with the regular stack. */ + +static int __attribute__ ((noinline)) +function_bl (void) +{ + register int x0 __asm__("x0"); + + __asm__ ("bl function2\n" + : "=r"(x0) + : + : "x30"); + + return x0; +} + +static int __attribute__ ((noinline)) +function_blr (void) +{ + register int x0 __asm__("x0"); + + __asm__ ("blr %1\n" + : "=r"(x0) + : "r"(&function2) + : "x30"); + + return x0; +} + +int +main (void) +{ + if (!(getauxval (AT_HWCAP) & HWCAP_GCS)) + { + fprintf (stderr, "GCS support not found in AT_HWCAP\n"); + return EXIT_FAILURE; + } + + /* Force shadow stacks on, our tests *should* be fine with or + without libc support and with or without this having ended + up tagged for GCS and enabled by the dynamic linker. We + can't use the libc prctl() function since we can't return + from enabling the stack. */ + unsigned long gcs_mode; + int ret = my_syscall2 (__NR_prctl, PR_GET_SHADOW_STACK_STATUS, &gcs_mode); + if (ret) + { + fprintf (stderr, "Failed to read GCS state: %d\n", ret); + return EXIT_FAILURE; + } + + if (!(gcs_mode & PR_SHADOW_STACK_ENABLE)) + { + gcs_mode = PR_SHADOW_STACK_ENABLE; + ret = my_syscall2 (__NR_prctl, PR_SET_SHADOW_STACK_STATUS, gcs_mode); + if (ret) + { + fprintf (stderr, "Failed to configure GCS: %d\n", ret); + return EXIT_FAILURE; + } + } + + int ret1 = function_bl (); + int ret2 = function_blr (); + + /* Avoid returning, in case libc doesn't understand GCS. */ + exit (ret1 + ret2); +} diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.exp b/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.exp new file mode 100644 index 000000000000..10b09a4d980e --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-gcs-disp-step.exp @@ -0,0 +1,90 @@ +# Copyright 2025 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Test displaced stepping in a program that uses a Guarded Control Stack. + +require allow_aarch64_gcs_tests + +standard_testfile + +if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } { + return +} + +if ![runto_main] { + return +} + +gdb_test_no_output "set breakpoint auto-hw off" +gdb_test_no_output "set displaced-stepping on" + +# Get address of the branch and link instructions of interest. +set addr_bl 0 +set test "get address of bl instruction" +gdb_test_multiple "disassemble function_bl" $test -lbl { + -re "\r\n\\s+($hex) <\\+${decimal}>:\\s+bl\\s+${hex} (?=\r\n)" { + set addr_bl $expect_out(1,string) + exp_continue + } + -re "$::gdb_prompt \$" { + gdb_assert { $addr_bl != 0 } $test + } +} + +set addr_blr 0 +set test "get address of blr instruction" +gdb_test_multiple "disassemble function_blr" $test -lbl { + -re "\r\n\\s+($hex) <\\+${decimal}>:\\s+blr\\s+x${decimal}(?=\r\n)" { + set addr_blr $expect_out(1,string) + exp_continue + } + -re "$::gdb_prompt \$" { + gdb_assert { $addr_blr != 0 } $test + } +} + +if { $addr_bl == 0 || $addr_blr == 0 } { + return +} + +gdb_test "break *$addr_bl" \ + "Breakpoint $decimal at $hex: file .*aarch64-gcs-disp-step.c, line ${decimal}." \ + "set breakpoint at bl instruction" + +gdb_test "break *$addr_blr" \ + "Breakpoint $decimal at $hex: file .*aarch64-gcs-disp-step.c, line ${decimal}." \ + "set breakpoint at blr instruction" + +gdb_test "continue" \ + [multi_line \ + {Continuing\.} \ + "" \ + "Breakpoint $decimal, function_bl \\(\\) at .*aarch64-gcs-disp-step.c:${decimal}(?: \\\[GCS error\\\])?" \ + {[^\r\n]+"bl function2\\n"}] \ + "continue to breakpoint at bl" + +gdb_test "continue" \ + [multi_line \ + {Continuing\.} \ + "" \ + "Breakpoint $decimal, $hex in function_blr \\(\\) at .*aarch64-gcs-disp-step.c:${decimal}(?: \\\[GCS error\\\])?" \ + {[^\r\n]+"blr %1\\n"}] \ + "continue to breakpoint at blr" + +gdb_test "continue" \ + [multi_line \ + "Continuing\\." \ + "\\\[Inferior 1 \\(process $decimal\\) exited normally\\\]"] \ + "continue until inferior exits"