From patchwork Sun Jun 22 01:18:10 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: 899064 Delivered-To: patch@linaro.org Received: by 2002:adf:e506:0:b0:3a6:d909:26ce with SMTP id j6csp370902wrm; Sat, 21 Jun 2025 21:09:07 -0700 (PDT) X-Forwarded-Encrypted: i=3; AJvYcCUAAPe7CqXe75BGZVsP03kBPw0LBp0A7bB2oamV+LESuDih0U2d4ezp8ya7byQiGIERk/V8Bg==@linaro.org X-Google-Smtp-Source: AGHT+IFnFMCKa5fn7nDLKynBNC6uHJEnvWwSIJI+2eHWNG6FAxkRzHwaMRUG/J3dhuuCYqroq4rd X-Received: by 2002:a05:6214:2427:b0:6fb:107:f618 with SMTP id 6a1803df08f44-6fd0a5adf82mr120494086d6.40.1750565347059; Sat, 21 Jun 2025 21:09:07 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1750565347; cv=pass; d=google.com; s=arc-20240605; b=Rh1QXDjUDKM8PafrHsrMe47bUEnHdMer5T3xeZU/7uWPCgmlqluq3XTntGcx8iEGwV PV0FWuTxsaLO+PTJtFLzlt7KYjBXjv37qpDeMxPCQSz1r5QwNmSZJxHnLf8B/sle44Ol Hvi9hgEOtpCwhsn7Ov3orKvgMII+eWKiPURIkAvvB0Hr5UyGU7FzXL55yObKH7jnQXpv z2EzlydOy8ZCakaevOQAXOtre+y2MuRGf1W1Zw938jRaqBhvirn3znaQE6AtoTMMiYnq rKc+ePdCnL4GN4pEB1HDDQLiKKNNDUPy/Yp1R3ulA00Ya9RJhDpUA6AbUC26Gx1Y0xET pV5g== 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=XdP+NYfiqCrU7Cj7xmAeAGA4TFktOo9EQLv16wXoccY=; fh=v0Swrqm/HGzmFfs2Lyn4KGEK39u4NVWMm4qGXeDZh/s=; b=KHUJ1wGUtmF7Bi68RNhy/iDw7bUScEt2toaByLGwUferBvFXm8ywNWZoijuJcqJIeD VzMztHDD2hMqULdESdo1iejxjsjGCTDnJMKa98qOl+SfeJ/CXq0U5NVD1n/SY6HXbohO kJL559RyvLv3f6CTdo+rlujM4j6Nc009F6uxE9yFVGWHMdH3HpMWFyaWXhqLxsM5cCdn RMNYG9M7/UTsIZNxpY5EgFcRV9D96paLFz367Em8lC5weEavYPeiB5E4FtRfisilW+tK 7h98wGFgdfnpCdZM3Tryj4QNfvbzqeHKJ1upGiVE4tujaWDRyh7LdfbCpiOiQlCDDLWz 4K0w==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b="p+JACMp/"; 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 6a1803df08f44-6fd093e15f1si55560576d6.33.2025.06.21.21.09.06 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 21 Jun 2025 21:09:07 -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="p+JACMp/"; 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 010D839948B7 for ; Sun, 22 Jun 2025 03:05:18 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 010D839948B7 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=p+JACMp/ X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail-pf1-x430.google.com (mail-pf1-x430.google.com [IPv6:2607:f8b0:4864:20::430]) by sourceware.org (Postfix) with ESMTPS id DD15B38101B9 for ; Sun, 22 Jun 2025 01:18:39 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org DD15B38101B9 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 DD15B38101B9 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::430 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1750555120; cv=none; b=wxXrahjJg6t2yEixWtOdQSeh5M/ZYMXEDgzZJQrHdWHNSRWGsdao1hzGZlTc1kCwpqqgvSL7gon/r40Z+mnHkfQcH2Qd8KifebXKO0i91V60Du+Ps+Hau/gAQlPtt7QduLQKvntItuzbjrVyZGbs1lbYIe6AsLh8oxHdLTHyf70= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1750555120; c=relaxed/simple; bh=Jl5HHGrBnhvKAoWNgaxviCSr+GwYp0rIZx7kDzoTL/A=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=cXGLB6qtdQG230X3kOnb2s3XAv67LfXMAkF2LqXk6i34eig1DGH6Q3CicZd+rILsXbfpDq9Vc0f+2MogTmQ5Br/mgRPuQSIdDDXYggQ1UzTsSydaifwAJ+WKlIJoKTwjS6pbzd1pSknWDvxqPk+h71CB1vNoNkfX6lXJ4kWsS8g= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org DD15B38101B9 Received: by mail-pf1-x430.google.com with SMTP id d2e1a72fcca58-747e41d5469so3162839b3a.3 for ; Sat, 21 Jun 2025 18:18:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1750555119; x=1751159919; 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=XdP+NYfiqCrU7Cj7xmAeAGA4TFktOo9EQLv16wXoccY=; b=p+JACMp/qTROyrk6Tzxc5xPEgDoUbt0f1OEYm24f5wVduNznFI6j2om2uEZMtn3ee0 ZlhPGhK4Rn2GgwnAurO5mbHjarJgR1V7/OoRmC/K3uXIwU6uRoAiFTPwrRudV7O5I8Vd mq8LfibQQkAQC/43/8a5Paba3YLsOoNJ022jMrkxdYMWIJJSXjW36Zbji84A+WZlsfUl O6wI58Dj4EwgXzT/C0+LX3kLNcjyYzsuziwtOhzOqgP+6cn/+1+Em0v22OWRhd3su0AF WPvq6I7uQJmZKz3TfY73x4ch311qgnGOM4oKXm/lk+azKd5bG/m4LRsa4tWy2JaUEkDB 7+Hw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1750555119; x=1751159919; 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=XdP+NYfiqCrU7Cj7xmAeAGA4TFktOo9EQLv16wXoccY=; b=UIM0pMgBUMl/sLEAiXErpWZ1qerLi3bFekVKIfcxZR2sOLXuab+VRCrVK0Q3QXXTrq nSpNHXawcnWhtdk3nCVOKfYRu55nlWMUQnxNW6z5Kea/r37KU2h0t9LYa4kT+ZIqpR/t Yv4ahCYrW6rTS3wRpm0AWlWjzcC9bjFhwMh3DGqWXlc4kswtxM8Bb1sDEjuMkhlK7IEw Ds5YJK7A27tHvy5MGdojsWlT1hpNbq6Qh0f0zyK5rfvvwNmm6wEFKYEI17H3YkypHY8f maJYfI7uHBATcpPxebmSnTTlealIQK7oR4aEfBG/wPQCeHWwDGYWklGWKBTQa4X3PPJi u0Lg== X-Gm-Message-State: AOJu0YwaHebyjgogYTsFmKg64ugphMRjLPtOdPgpk58Co3gCku6eLf1s so9dRIFQSDGpj9L6Ko4FlY/nfXe+vJbgyAkIq5lU/13JykVHy57vq896aPV3W0lqsX9vkLG+ZQy yHNTl X-Gm-Gg: ASbGncvQFq4ty/6T/dsplbCFH42KSAvvq5AY5iwMSwqv9c0K7bqvG+lWNT/TWg8u2mI E00nXfw+b48WyTAlDD7/U7FRViRLcZ1GbZ0g8oc/AUq9Sg43weBV2TWAT37E/pCJMuUG6iN0K0+ 6kDidwvfbo+FLK82hZk1xalN3M4aPAduGB7VrxeHgrRb2tahurYr5v9WZ9L2QRzc3R3IMMlnIjS 4s9YG0jV+yFm1/cNSS8l6ulkHM+RgIiRd+wmHTdzEjwryhB8PtUYNvPVyNLPqCPtnTZ1KiZbZZk sUb7si9J9iTq20TOWZnf0TkPsaBm9wQfGc0cMHu9SETi3ruU3G6dBEyrplo6GhP1aKf2BR/td1A s7yEV/jc= X-Received: by 2002:a05:6a00:2e99:b0:742:b3a6:db16 with SMTP id d2e1a72fcca58-7490d67f737mr10673445b3a.20.1750555118835; Sat, 21 Jun 2025 18:18:38 -0700 (PDT) Received: from localhost ([2804:14d:7e39:88d6:79ae:7a30:10f3:dfed]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-7490a48a1b6sm5265155b3a.50.2025.06.21.18.18.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 21 Jun 2025 18:18:38 -0700 (PDT) From: Thiago Jung Bauermann To: gdb-patches@sourceware.org Cc: Eli Zaretskii , "Schimpe, Christina" , Luis Machado Subject: [PATCH v3 8/9] GDB: aarch64-linux: Support unwinding the GCSPR Date: Sat, 21 Jun 2025 22:18:10 -0300 Message-ID: <20250622011811.371949-9-thiago.bauermann@linaro.org> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250622011811.371949-1-thiago.bauermann@linaro.org> References: <20250622011811.371949-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 The GCSPR is almost always updated implicitly by the hardware, so the compiler doesn't generate DWARF unwind information for it. Therefore add an unwinding function that calculates the value of the GCSPR in the previous frame based on its value in this frame. Some sanity checking is done by confirming that the calculated value is within a Guarded Control Stack memory area. This function is the same as amd64_linux_dwarf2_prev_ssp, written by Christina Schimpe to unwind Intel's SSP register. The gdb.arch/aarch64-gcs-return.exp testcase is lightly adapted from gdb.arch/amd64-shadow-stack-cmds.exp. Approved-By: Luis Machado --- The code and testcase are lightly adapted from: [PATCH v4 07/11] gdb: Handle shadow stack pointer register unwinding for amd64 linux. https://inbox.sourceware.org/gdb-patches/20250617121147.1956686-8-christina.schimpe@intel.com/ Changes since v2: - Fix off-by-one error in new_gcspr comparison with GCS memory range, and clarify comment (suggested by Luis). gdb/aarch64-linux-tdep.c | 54 ++++++- gdb/aarch64-tdep.c | 6 + gdb/aarch64-tdep.h | 4 + gdb/testsuite/gdb.arch/aarch64-gcs-return.c | 105 ++++++++++++++ gdb/testsuite/gdb.arch/aarch64-gcs-return.exp | 132 ++++++++++++++++++ 5 files changed, 300 insertions(+), 1 deletion(-) create mode 100644 gdb/testsuite/gdb.arch/aarch64-gcs-return.c create mode 100644 gdb/testsuite/gdb.arch/aarch64-gcs-return.exp diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c index 0538412ce554..1335d0424f26 100644 --- a/gdb/aarch64-linux-tdep.c +++ b/gdb/aarch64-linux-tdep.c @@ -32,6 +32,7 @@ #include "symtab.h" #include "tramp-frame.h" #include "trad-frame.h" +#include "dwarf2/frame.h" #include "target.h" #include "target/target.h" #include "expop.h" @@ -2561,6 +2562,54 @@ aarch64_linux_get_shadow_stack_pointer (gdbarch *gdbarch, regcache *regcache, return gcspr; } +/* Implement Guarded Control Stack Pointer Register unwinding. For each + previous GCS pointer check if its address is still in the GCS memory + range. If it's outside the range set the returned value to unavailable, + otherwise return a value containing the new GCS pointer. */ + +static value * +aarch64_linux_dwarf2_prev_gcspr (const frame_info_ptr &this_frame, + void **this_cache, int regnum) +{ + value *v = frame_unwind_got_register (this_frame, regnum, regnum); + gdb_assert (v != nullptr); + + gdbarch *gdbarch = get_frame_arch (this_frame); + + if (v->entirely_available () && !v->optimized_out ()) + { + int size = register_size (gdbarch, regnum); + bfd_endian byte_order = gdbarch_byte_order (gdbarch); + CORE_ADDR gcspr = extract_unsigned_integer (v->contents_all ().data (), + size, byte_order); + + /* Starting with v6.13, the Linux kernel supports Guarded Control + Stack. Using /proc/PID/smaps we can only check if the current + GCSPR points to GCS memory. Only if this is the case a valid + previous GCS pointer can be calculated. */ + std::pair range; + if (linux_address_in_shadow_stack_mem_range (gcspr, &range)) + { + /* The GCS grows downwards. To compute the previous GCS pointer, + we need to increment the GCSPR. */ + CORE_ADDR new_gcspr = gcspr + 8; + + /* If NEW_GCSPR still points within the current GCS memory range + we consider it to be valid. */ + if (new_gcspr < range.second) + return frame_unwind_got_address (this_frame, regnum, new_gcspr); + } + } + + /* Return a value which is marked as unavailable in case we could not + calculate a valid previous GCS pointer. */ + value *retval + = value::allocate_register (get_next_frame_sentinel_okay (this_frame), + regnum, register_type (gdbarch, regnum)); + retval->mark_bytes_unavailable (0, retval->type ()->length ()); + return retval; +} + /* AArch64 Linux implementation of the report_signal_info gdbarch hook. Displays information about possible memory tag violations. */ @@ -3138,8 +3187,11 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) aarch64_use_target_description_from_corefile_notes); if (tdep->has_gcs_linux ()) - set_gdbarch_get_shadow_stack_pointer (gdbarch, + { + set_gdbarch_get_shadow_stack_pointer (gdbarch, aarch64_linux_get_shadow_stack_pointer); + tdep->fn_prev_gcspr = aarch64_linux_dwarf2_prev_gcspr; + } } #if GDB_SELF_TEST diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c index e21c4a8e9ae1..c479a0b70323 100644 --- a/gdb/aarch64-tdep.c +++ b/gdb/aarch64-tdep.c @@ -1408,6 +1408,12 @@ aarch64_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum, return; } } + if (tdep->has_gcs () && tdep->fn_prev_gcspr != nullptr + && regnum == tdep->gcs_reg_base) + { + reg->how = DWARF2_FRAME_REG_FN; + reg->loc.fn = tdep->fn_prev_gcspr; + } } /* Implement the execute_dwarf_cfa_vendor_op method. */ diff --git a/gdb/aarch64-tdep.h b/gdb/aarch64-tdep.h index 54ca641a35a3..99e7d26ce4ab 100644 --- a/gdb/aarch64-tdep.h +++ b/gdb/aarch64-tdep.h @@ -23,6 +23,7 @@ #define GDB_AARCH64_TDEP_H #include "arch/aarch64.h" +#include "dwarf2/frame.h" #include "displaced-stepping.h" #include "infrun.h" #include "gdbarch.h" @@ -190,6 +191,9 @@ struct aarch64_gdbarch_tdep : gdbarch_tdep_base available. */ int gcs_linux_reg_base = -1; + /* Function to unwind the GCSPR from the given frame. */ + fn_prev_register fn_prev_gcspr = nullptr; + /* Returns true if the target supports GCS. */ bool has_gcs () const diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs-return.c b/gdb/testsuite/gdb.arch/aarch64-gcs-return.c new file mode 100644 index 000000000000..c6ade8af7e9f --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-gcs-return.c @@ -0,0 +1,105 @@ +/* This test program is part of GDB, the GNU debugger. + + Copyright 2025 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#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; \ + }) + +static int __attribute__ ((noinline)) +call2 () +{ + return 42; /* Break call2. */ +} + +static int __attribute__ ((noinline)) +call1 () +{ + return call2 (); /* Break call1. */ +} + +int +main () +{ + if (!(getauxval (AT_HWCAP) & HWCAP_GCS)) + { + fprintf (stderr, "GCS support not found in AT_HWCAP\n"); + return EXIT_FAILURE; + } + + /* Force shadow stacks on, our tests *should* be fine with or + without libc support and with or without this having ended + up tagged for GCS and enabled by the dynamic linker. We + can't use the libc prctl() function since we can't return + from enabling the stack. Also lock GCS if not already + locked so we can test behaviour when it's locked. */ + unsigned long gcs_mode; + int ret = my_syscall2 (__NR_prctl, PR_GET_SHADOW_STACK_STATUS, &gcs_mode); + if (ret) + { + fprintf (stderr, "Failed to read GCS state: %d\n", ret); + return EXIT_FAILURE; + } + + if (!(gcs_mode & PR_SHADOW_STACK_ENABLE)) + { + gcs_mode = PR_SHADOW_STACK_ENABLE; + ret = my_syscall2 (__NR_prctl, PR_SET_SHADOW_STACK_STATUS, gcs_mode); + if (ret) + { + fprintf (stderr, "Failed to configure GCS: %d\n", ret); + return EXIT_FAILURE; + } + } + + call1 (); /* Break main. */ + + /* Avoid returning, in case libc doesn't understand GCS. */ + exit (EXIT_SUCCESS); +} diff --git a/gdb/testsuite/gdb.arch/aarch64-gcs-return.exp b/gdb/testsuite/gdb.arch/aarch64-gcs-return.exp new file mode 100644 index 000000000000..717cc305c25c --- /dev/null +++ b/gdb/testsuite/gdb.arch/aarch64-gcs-return.exp @@ -0,0 +1,132 @@ +# 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 the GDB return command in a program that uses a Guarded Control Stack. +# Based on the return tests in gdb.arch/amd64-shadow-stack-cmds.exp. + +require allow_aarch64_gcs_tests + +standard_testfile + +if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } { + return +} + +set main_line [gdb_get_line_number "Break main"] +set call1_line [gdb_get_line_number "Break call1"] +set call2_line [gdb_get_line_number "Break call2"] + +if { ![runto ${main_line}] } { + return +} + +proc restart_and_run_infcall_call2 {} { + global binfile call2_line + clean_restart ${binfile} + if { ![runto_main] } { + return + } + set inside_infcall_str "The program being debugged stopped while in a function called from GDB" + gdb_breakpoint ${call2_line} + gdb_continue_to_breakpoint "Break call2" ".*Break call2.*" + gdb_test "call (int) call2()" \ + "Breakpoint \[0-9\]*, call2.*$inside_infcall_str.*" +} + +with_test_prefix "test inferior call and continue" { + gdb_breakpoint ${call1_line} + gdb_continue_to_breakpoint "Break call1" ".*Break call1.*" + + gdb_test "call (int) call2()" "= 42" + + gdb_continue_to_end +} + +with_test_prefix "test return inside an inferior call" { + restart_and_run_infcall_call2 + + gdb_test "return" "\#0.*call2.*" \ + "Test GCS return inside an inferior call" \ + "Make.*return now\\? \\(y or n\\) " "y" + + gdb_continue_to_end +} + +with_test_prefix "test return 'above' an inferior call" { + restart_and_run_infcall_call2 + + gdb_test "frame 2" "call2 ().*" "move to frame 'above' inferior call" + + gdb_test "return" "\#0.*call1.*" \ + "Test GCS return 'above' an inferior call" \ + "Make.*return now\\? \\(y or n\\) " "y" + + gdb_continue_to_end +} + +clean_restart ${binfile} +if { ![runto ${main_line}] } { + return +} + +# Extract GCS pointer inside main, call1 and call2 function. +gdb_breakpoint ${call1_line} +gdb_breakpoint ${call2_line} +set gcspr_main [get_valueof /x "\$gcspr" 0 "get value of gcspr in main"] +gdb_continue_to_breakpoint "Break call1" ".*Break call1.*" +set gcspr_call1 [get_valueof /x "\$gcspr" 0 "get value of gcspr in call1"] +gdb_continue_to_breakpoint "Break call2" ".*Break call2.*" +set gcspr_call2 [get_valueof /x "\$gcspr" 0 "get value of gcspr in call2"] + +with_test_prefix "test frame level update" { + gdb_test "up" "call1.*" "move to frame 1" + gdb_test "print /x \$gcspr" "= $gcspr_call1" "check gcspr of frame 1" + gdb_test "up" "main.*" "move to frame 2" + gdb_test "print /x \$gcspr" "= $gcspr_main" "check gcspr of frame 2" + gdb_test "frame 0" "call2.*" "move to frame 0" + gdb_test "print /x \$gcspr" "= $gcspr_call2" "check gcspr of frame 0" +} + +with_test_prefix "test return from current frame" { + gdb_test "return (int) 1" "#0.*call1.*" \ + "Test GCS return from current frame" \ + "Make.*return now\\? \\(y or n\\) " "y" + + # Potential GCS violations often only occur after resuming normal + # execution. Therefore, it is important to test normal program + # continuation after testing the return command. + gdb_continue_to_end +} + +clean_restart ${binfile} +if { ![runto_main] } { + return +} + +with_test_prefix "test return from past frame" { + gdb_breakpoint ${call2_line} + gdb_continue_to_breakpoint "Break call2" ".*Break call2.*" + + gdb_test "frame 1" ".*in call1.*" + + gdb_test "return (int) 1" "#0.*main.*" \ + "Test GCS return from past frame" \ + "Make.*return now\\? \\(y or n\\) " "y" + + # Potential GCS violations often only occur after resuming normal + # execution. Therefore, it is important to test normal program + # continuation after testing the return command. + gdb_continue_to_end +}