Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Guinevere Larsen <guinevere@redhat.com>
To: Ezra.Sitorus@arm.com, gdb-patches@sourceware.org
Cc: luis.machado.foss@gmail.com, thiago.bauermann@linaro.org
Subject: Re: [PATCH 1/4] gdb/aarch64: record/replay support for LRCPC3
Date: Fri, 24 Apr 2026 12:09:53 -0300	[thread overview]
Message-ID: <76af2403-c565-418d-b730-10b0490565db@redhat.com> (raw)
In-Reply-To: <20260420215232.68675-2-Ezra.Sitorus@arm.com>

On 4/20/26 6:52 PM, Ezra.Sitorus@arm.com wrote:
> From: Ezra Sitorus <ezra.sitorus@arm.com>
>
> FEAT_LRCPC3 introduces various load/store instructions with release
> consistency for cases where ordering is required. This patch teaches GDB
> to decode these instructions for recording and reversing.
>
> The gdb.reverse/aarch64-lrcpc3.exp testcase verifies that the
> instructions are recorded and correctly reversed. In particular, there
> are some interesting cases to note:
> * ldapur/stlur are SIMD instructions, but are not decoded in the simd
>    function.
> * There are writeback cases to cover too. These were taken from the
>    binutils testcases: gas/testsuite/gas/aarch64/rcpc3.s.
>
> The full testsuite was done on aarch64-none-linux-gnu without LRCPC3.
> The gdb.arch and gdb.reverse tests were run on Shrinkwrap with LRCPC3
> support.
>
> Please note:
> 1) There is no support for LRCPC and LRCPC2 instructions
> 2) LRCPC3 is gated with +rcpc3 in GCC/binutils.
> ---

Hi! Thanks for working on this!

I can't really comment on the aarch64-tdep bits, but I did notice a few 
minor things in the test that could be improved.

>   gdb/aarch64-tdep.c                           |  87 +++++
>   gdb/testsuite/gdb.reverse/aarch64-lrcpc3.c   | 319 +++++++++++++++++++
>   gdb/testsuite/gdb.reverse/aarch64-lrcpc3.exp | 203 ++++++++++++
>   gdb/testsuite/lib/gdb.exp                    |  63 ++++
>   4 files changed, 672 insertions(+)
>   create mode 100644 gdb/testsuite/gdb.reverse/aarch64-lrcpc3.c
>   create mode 100644 gdb/testsuite/gdb.reverse/aarch64-lrcpc3.exp
>
> diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c
> index 4befaa2720d..81d4f160f8f 100644
> --- a/gdb/aarch64-tdep.c
> +++ b/gdb/aarch64-tdep.c
> @@ -5812,6 +5812,93 @@ aarch64_record_load_store (aarch64_insn_decode_record *aarch64_insn_r)
>   	  aarch64_insn_r->reg_rec_count = 1;
>   	}
>       }
> +  /* LRCPC3 instructions.  This covers ldiapp/stilp, ldapur/stlur (FP/SIMD),
> +     ldapr/stlr.  */
> +  else if ((insn_bits24_27 & 0x0b) == 0x09 && insn_bits28_29 == 0x01
> +	   && insn_bits10_11 == 0x02 && !insn_bit21)
> +    {
> +      /* ldapur/stlur (FP/SIMD), ldapr/stlr.  We can differentiate between the
> +	 2 types by checking the vector flag.  */
> +      if (insn_bit23 || vector_flag)
> +	{
> +	  /* For the vector instruction, the offset comes from the imm9
> +	     bitfield, whereas the other can only take possible values from the
> +	     size bitfield.  */
> +	  int16_t imm9_off = sbits (aarch64_insn_r->aarch64_insn, 12, 20);
> +	  offset = vector_flag ? imm9_off : -(1 << size_bits);
> +	  uint32_t regnum_offset = vector_flag ? AARCH64_V0_REGNUM : 0;
> +	  if (ld_flag)
> +	    {
> +	      record_buf[0] = reg_rt + regnum_offset;
> +	      aarch64_insn_r->reg_rec_count = 1;
> +	      if (!vector_flag)
> +		{
> +		  /* The Rn register always has writeback in LRCPC3. This is
> +		     not the case in LRCPC.  */
> +		  record_buf[1] = reg_rn;
> +		  aarch64_insn_r->reg_rec_count = 2;
> +		}
> +	    }
> +	  else
> +	    {
> +	      regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn,
> +					  &address);
> +	      /* (vector_flag && insn_bit23) is the STLUR instruction with Q
> +		 register.  */
> +	      datasize = (vector_flag && insn_bit23) ? 128 : (8 << size_bits);
> +	      /* LRCPC3 adds STLR with a pre-indexed offset. There is another
> +		 STLR variant without offset but this has a different encoding.  */
> +	      if (!vector_flag)
> +		{
> +		  record_buf[0] = reg_rn;
> +		  aarch64_insn_r->reg_rec_count = 1;
> +		}
> +	      record_buf_mem[0] = datasize >> 3;
> +	      record_buf_mem[1] = address + offset;
> +	      aarch64_insn_r->mem_rec_count = 1;
> +	    }
> +	}
> +      else
> +	{
> +	  /* ldiapp/stilp.  */
> +	  uint8_t opc2 = bits (aarch64_insn_r->aarch64_insn, 12, 15);
> +	  reg_rt2 = bits (aarch64_insn_r->aarch64_insn, 16, 20);
> +	  if (ld_flag)
> +	    {
> +	      record_buf[0] = reg_rt;
> +	      record_buf[1] = reg_rt2;
> +	      aarch64_insn_r->reg_rec_count = 2;
> +
> +	      /* If the registers don't match and there's no offset then
> +	         there's WB.  */
> +	      if (reg_rn != reg_rt && reg_rn != reg_rt2 && opc2 == 0)
> +		{
> +		  record_buf[2] = reg_rn;
> +		  aarch64_insn_r->reg_rec_count = 3;
> +		}
> +	    }
> +	  else
> +	    {
> +	      datasize = 8 << size_bits;
> +	      regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rn,
> +					  &address);
> +	      offset = (opc2 == 0) ? (2 << size_bits) : 0;
> +	      address -= offset;
> +
> +	      record_buf_mem[0] = datasize >> 3;
> +	      record_buf_mem[1] = address;
> +	      record_buf_mem[2] = datasize >> 3;
> +	      record_buf_mem[3] = address + (datasize >> 3);
> +	      aarch64_insn_r->mem_rec_count = 2;
> +
> +	      if (offset != 0)
> +		{
> +		  record_buf[0] = reg_rn;
> +		  aarch64_insn_r->reg_rec_count = 1;
> +		}
> +	    }
> +	}
> +    }
>     /* Load/store register (register offset) instructions.  */
>     else if ((insn_bits24_27 & 0x0b) == 0x08 && insn_bits28_29 == 0x03
>   	   && insn_bits10_11 == 0x02 && insn_bit21)
> diff --git a/gdb/testsuite/gdb.reverse/aarch64-lrcpc3.c b/gdb/testsuite/gdb.reverse/aarch64-lrcpc3.c
> new file mode 100644
> index 00000000000..9265489ff70
> --- /dev/null
> +++ b/gdb/testsuite/gdb.reverse/aarch64-lrcpc3.c
> @@ -0,0 +1,319 @@
> +/* This test program is part of GDB, the GNU debugger.
> +
> +   Copyright 2024-2026 Free Software Foundation, Inc.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +#include <stdint.h>
> +#include <stdalign.h>
> +#include <string.h>
> +
> +#define INITIAL_STRING "This is just some string."
> +#define BUF_SIZE sizeof (INITIAL_STRING)
> +
> +#define PREPARE_FOR_LOAD(OFFSET) \
> +	__asm__ volatile ("mov %0, #0\n" : "=r"(xa)::); \
> +	__asm__ volatile ("mov %0, #0\n" : "=r"(xb)::); \
> +	strcpy (src, INITIAL_STRING); \
> +	ptr = (uint64_t *)((uint8_t *)src + OFFSET); \
> +
> +#define PREPARE_FOR_VECTOR_LOAD(OFFSET) \
> +	__asm__ volatile ("movi %0.2d, #0\n" : "=w"(va)::); \
> +	strcpy (src, INITIAL_STRING); \
> +	ptr = (uint64_t *)((uint8_t *)src + OFFSET); \
> +
> +#define PREPARE_FOR_STORE(OFFSET) \
> +	__asm__ volatile ("mov %0, #0\n" : "=r"(xa)::); \
> +	__asm__ volatile ("mov %0, #0\n" : "=r"(xb)::); \
> +	strcpy (src, INITIAL_STRING); \
> +	ptr = (uint64_t *)((uint8_t *)src + OFFSET); \
> +
> +#define PREPARE_FOR_VECTOR_STORE(OFFSET) \
> +	__asm__ volatile ("movi %0.2d, #0\n" : "=w"(va)::); \
> +	strcpy (src, INITIAL_STRING); \
> +	ptr = (uint64_t *)((uint8_t *)src + OFFSET); \
All of these macros have the same strcpy and ptr assignment code in 
them. I think it would be more clear if you made one macro for that part 
and the rest either have that macro, or just be in the code directly.
> +
> +typedef uint64_t uint64x2_t __attribute__((vector_size(16)));
> +
> +int
> +main (void)
> +{
> +  alignas(16) char src[BUF_SIZE];
> +
> +  register uint64_t xa asm ("x19");
> +  register uint32_t xb asm ("x20");
> +  register uint64_t *ptr asm ("x21");
> +  register uint64x2_t va asm ("v22");

The register keyword is a hint for the compiler, and has been deprecated 
since c++11. I know that clang always ignores the keyword and I think 
GCC is free to do so under some circumstances.

Considering that the rest of the test doesn't access the variables in 
any way that isn't assembly code, you're free to write the registers 
directly there. I did see that in the exp file you check for the value 
of the variable, however, if you're already checking the register, there 
isn't anything special that checking the variable would do, it is in 
fact closer to double checking that the compiler actually did what you 
told it to do. You can just drop the variable and examine only the 
registers.

> +
> +  PREPARE_FOR_LOAD (0);
> +  /* Before ldiapp-0.  */
> +  __asm__ volatile ("ldiapp %0, %1, [%2]\n"
> +		    : "=r"(xa), "=r"(xb)
> +		    : "r"(ptr)
> +		    : "memory");
For example, writing __asm__ volatile ("ldiapp x19, x20, [%0]", : : "r" 
(ptr) : "memory");
> +  /* After ldiapp-0.  */
> +
> +  PREPARE_FOR_LOAD (0);
> +  /* Before ldiapp-1.  */
> +  __asm__ volatile ("ldiapp %w0, %w1, [%2]\n"
> +		    : "=r"(xa), "=r"(xb)
> +		    : "r"(ptr)
> +		    : "memory");
> +  /* After ldiapp-1.  */
> +
> +  PREPARE_FOR_LOAD (0);
> +  /* Before ldiapp-2.  */
> +  __asm__ volatile ("ldiapp %0, %1, [%2], #16\n"
> +		    : "=r"(xa), "=r"(xb)
> +		    : "r"(ptr)
> +		    : "memory");
> +  /* After ldiapp-2.  */
> +
> +  PREPARE_FOR_LOAD (0);
> +  /* Before ldiapp-3.  */
> +  __asm__ volatile ("ldiapp %w0, %w1, [%2], #8\n"
> +		    : "=r"(xa), "=r"(xb)
> +		    : "r"(ptr)
> +		    : "memory");
> +  /* After ldiapp-3.  */
> +  /* Register overlap between source and destination registers.  Since there is
> +     no offset, writeback is disabled.  */
> +
> +  PREPARE_FOR_LOAD (0);
> +  /* Before ldiapp-4.  */
> +  __asm__ volatile ("ldiapp %0, %1, [%0]\n"
> +		    : "+r"(ptr), "=r"(xb)
> +		    :
> +		    : "memory");
> +  /* After ldiapp-4.  */
> +
> +  PREPARE_FOR_LOAD (0);
> +  /* Before ldiapp-5.  */
> +  __asm__ volatile ("ldiapp %w0, %w1, [%0]\n"
> +		    : "+r"(ptr), "=r"(xb)
> +		    :
> +		    : "memory");
> +  /* After ldiapp-5.  */
> +
> +  PREPARE_FOR_STORE (0);
> +  /* Before stilp-0.  */
> +  __asm__ volatile ("stilp %0, %1, [%2]\n"
> +		    :
> +		    : "r"(xa), "r"(xb), "r"(ptr)
> +		    : "memory");
> +  /* After stilp-0.  */
> +
> +  PREPARE_FOR_STORE (0);
> +  /* Before stilp-1.  */
> +  __asm__ volatile ("stilp %w0, %w1, [%2]\n"
> +		    :
> +		    : "r"(xa), "r"(xb), "r"(ptr)
> +		    : "memory");
> +  /* After stilp-1.  */
> +
> +  PREPARE_FOR_STORE (16);
> +  /* Before stilp-2.  */
> +  __asm__ volatile ("stilp %1, %2, [%0, #-16]!\n"
> +		    : "+r"(ptr)
> +		    : "r"(xa), "r"(xb)
> +		    : "memory");
> +  /* After stilp-2.  */
> +
> +  PREPARE_FOR_STORE (8);
> +  /* Before stilp-3.  */
> +  __asm__ volatile ("stilp %w1, %w2, [%0, #-8]!\n"
> +		    : "+r"(ptr)
> +		    : "r"(xa), "r"(xb)
> +		    : "memory");
> +  /* After stilp-3.  */
> +  /* Register overlap.  Since there is no offset, writeback is disabled.  */
> +
> +  PREPARE_FOR_STORE (0);
> +  /* Before stilp-4.  */
> +  __asm__ volatile ("stilp %0, %1, [%0]\n"
> +		    :
> +		    : "r"(ptr), "r"(xb)
> +		    : "memory");
> +  /* After stilp-4.  */
> +
> +  PREPARE_FOR_STORE (0);
> +  /* Before stilp-5.  */
> +  __asm__ volatile ("stilp %w0, %w1, [%0]\n"
> +		    :
> +		    : "r"(ptr), "r"(xb)
> +		    : "memory");
> +  /* After stilp-5.  */
> +
> +  PREPARE_FOR_LOAD (0);
> +  /* Before ldapr-0.  */
> +  __asm__ volatile ("ldapr %0, [%1], #8\n"
> +		    : "+r"(xa), "+r"(ptr)
> +		    :
> +		    : "memory");
> +  /* After ldapr-0.  */
> +
> +  PREPARE_FOR_LOAD (0);
> +  /* Before ldapr-1.  */
> +  __asm__ volatile ("ldapr %w0, [%1], #4\n"
> +		    : "+r"(xa), "+r"(ptr)
> +		    :
> +		    : "memory");
> +  /* After ldapr-1.  */
> +
> +  PREPARE_FOR_STORE (8);
> +  /* Before stlr-0.  */
> +  __asm__ volatile ("stlr %1, [%0, #-8]!\n"
> +		    : "+r"(ptr)
> +		    : "r"(xa)
> +		    : "memory");
> +  /* After stlr-0.  */
> +
> +  PREPARE_FOR_STORE (4);
> +  /* Before stlr-1.  */
> +  __asm__ volatile ("stlr %w1, [%0, #-4]!\n"
> +		    : "+r"(ptr)
> +		    : "r"(xa)
> +		    : "memory");
> +  /* After stlr-1.  */
> +
> +  PREPARE_FOR_VECTOR_LOAD (0);
> +  /* Before ldap1-0.  */
> +  __asm__ volatile ("ldap1 {%0.d}[0], [%1]\n"
> +		    : "=w"(va)
> +		    : "r"(ptr)
> +		    : "memory");
> +  /* After ldap1-0.  */
> +
> +  PREPARE_FOR_VECTOR_STORE (0);
> +  /* Before stl1-0.  */
> +  __asm__ volatile ("stl1 {%0.d}[0], [%1]\n"
> +		    :
> +		    : "w"(va), "r"(ptr)
> +		    : "memory");
> +  /* After stl1-0.  */
> +
> +  PREPARE_FOR_VECTOR_LOAD (0);
> +  /* Before ldapur-0.  */
> +  __asm__ volatile ("ldapur %d0, [%1]\n"
> +		  : "=w"(va)
> +		  : "r"(ptr)
> +		  : "memory");
> +  /* After ldapur-0.  */
> +
> +  PREPARE_FOR_VECTOR_STORE (0);
> +  /* Before stlur-0.  */
> +  __asm__ volatile ("stlur %d0, [%1]\n"
> +		  :
> +		  : "w"(va), "r"(ptr)
> +		  : "memory");
> +  /* After stlur-0.  */
> +
> +  PREPARE_FOR_VECTOR_LOAD (256);
> +  /* Before ldapur-1.  */
> +  __asm__ volatile ("ldapur %d0, [%1, #-256]\n"
> +		    : "=w"(va)
> +		    : "r"(ptr)
> +		    : "memory");
> +  /* After ldapur-1.  */
> +
> +  PREPARE_FOR_VECTOR_STORE (256);
> +  /* Before stlur-1.  */
> +  __asm__ volatile ("stlur %d0, [%1, #-256]\n"
> +		    :
> +		    : "w"(va), "r"(ptr)
> +		    : "memory");
> +  /* After stlur-1.  */
> +
> +  PREPARE_FOR_VECTOR_LOAD (-255);
> +  /* Before ldapur-2.  */
> +  __asm__ volatile ("ldapur %d0, [%1, #255]\n"
> +		    : "=w"(va)
> +		    : "r"(ptr)
> +		    : "memory");
> +  /* After ldapur-2.  */
> +
> +  PREPARE_FOR_VECTOR_STORE (-255);
> +  /* Before stlur-2.  */
> +  __asm__ volatile ("stlur %d0, [%1, #255]\n"
> +		    :
> +		    : "w"(va), "r"(ptr)
> +		    : "memory");
> +  /* After stlur-2.  */
> +
> +  PREPARE_FOR_VECTOR_LOAD (0);
> +  /* Before ldapur-3.  */
> +  __asm__ volatile ("ldapur %h0, [%1]\n"
> +		  : "=w"(va)
> +		  : "r"(ptr)
> +		  : "memory");
> +  /* After ldapur-3.  */
> +
> +  PREPARE_FOR_VECTOR_STORE (0);
> +  /* Before stlur-3.  */
> +  __asm__ volatile ("stlur %h0, [%1]\n"
> +		  :
> +		  : "w"(va), "r"(ptr)
> +		  : "memory");
> +  /* After stlur-3.  */
> +
> +  PREPARE_FOR_VECTOR_LOAD (0);
> +  /* Before ldapur-4.  */
> +  __asm__ volatile ("ldapur %s0, [%1]\n"
> +		  : "=w"(va)
> +		  : "r"(ptr)
> +		  : "memory");
> +  /* After ldapur-4.  */
> +
> +  PREPARE_FOR_VECTOR_STORE (0);
> +  /* Before stlur-4.  */
> +  __asm__ volatile ("stlur %s0, [%1]\n"
> +		  :
> +		  : "w"(va), "r"(ptr)
> +		  : "memory");
> +  /* After stlur-4.  */
> +
> +  PREPARE_FOR_VECTOR_LOAD (0);
> +  /* Before ldapur-5.  */
> +  __asm__ volatile ("ldapur %d0, [%1]\n"
> +		  : "=w"(va)
> +		  : "r"(ptr)
> +		  : "memory");
> +  /* After ldapur-5.  */
> +
> +  PREPARE_FOR_VECTOR_STORE (0);
> +  /* Before stlur-5.  */
> +  __asm__ volatile ("stlur %d0, [%1]\n"
> +		  :
> +		  : "w"(va), "r"(ptr)
> +		  : "memory");
> +  /* After stlur-5.  */
> +
> +  PREPARE_FOR_VECTOR_LOAD (0);
> +  /* Before ldapur-6.  */
> +  __asm__ volatile ("ldapur %q0, [%1]\n"
> +		  : "=w"(va)
> +		  : "r"(ptr)
> +		  : "memory");
> +  /* After ldapur-6.  */
> +
> +  PREPARE_FOR_VECTOR_STORE (0);
> +  /* Before stlur-6.  */
> +  __asm__ volatile ("stlur %q0, [%1]\n"
> +		  :
> +		  : "w"(va), "r"(ptr)
> +		  : "memory");
> +  /* After stlur-6.  */
> +
> +  return 0;
> +}
> diff --git a/gdb/testsuite/gdb.reverse/aarch64-lrcpc3.exp b/gdb/testsuite/gdb.reverse/aarch64-lrcpc3.exp
> new file mode 100644
> index 00000000000..7d7a8c45445
> --- /dev/null
> +++ b/gdb/testsuite/gdb.reverse/aarch64-lrcpc3.exp
> @@ -0,0 +1,203 @@
> +# Copyright 2024-2026 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +
> +# Test instruction record for AArch64 FEAT_LRCPC3 instructions.
> +# Based on gdb.reverse/aarch64-mops.exp
> +#
> +# The basic flow of the record tests are:
> +#    1) Stop before executing the instructions of interest.  Record
> +#       the initial value of the registers that the instruction will
> +#       change, i.e. the destination register.
> +#    2) Execute the instructions.  Record the new value of the
> +#       registers that changed.
> +#    3) Reverse the direction of the execution and execute back to
> +#       just before the instructions of interest.  Record the final
> +#       value of the registers of interest.
> +#    4) Check that the initial and new values of the registers are
> +#       different, i.e. the instruction changed the registers as expected.
> +#    5) Check that the initial and final values of the registers are
> +#       the same, i.e. GDB record restored the registers to their
> +#       original values.
> +
> +require allow_aarch64_lrcpc3_tests
> +
> +standard_testfile
> +
> +if {
> +    [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \
> +	[list debug additional_flags=-march=armv8-a+rcpc3]]
> +} {
> +    return -1
> +}
> +
> +if {![runto_main]} {
> +    return -1
> +}
> +
> +gdb_test_no_output "record full"
> +
> +proc test_single_asm {name diff_reg diff_var diff_mem same_reg same_var same_mem} {
> +    global decimal hex
> +
> +    set before_seq [gdb_get_line_number "Before ${name}"]
> +    set after_seq [gdb_get_line_number "After ${name}"]
> +
> +    set insn [lindex [split $name "-"] 0]
> +
> +    gdb_test "break $before_seq" \
> +	"Breakpoint $decimal at $hex: file .*/aarch64-lrcpc3.c, line $decimal\\." \
> +	"$name: break before instruction sequence"
> +    gdb_continue_to_breakpoint "$name: about to execute instruction sequence" \
> +	[multi_line ".*/aarch64-lrcpc3.c:$decimal" \
> +	    "$decimal\[ \t\]+__asm__ volatile \\(\"${insn} \[^\r\n\]+\""]
> +
> +    # Depending on the compiler, the line number information may put GDB a few
> +    # instructions before the beginning of the asm statement.
> +    arrive_at_instruction $insn
> +    # Add a breakpoint that we're sure is at the prologue instruction.
> +    gdb_test "break *\$pc" \
> +	"Breakpoint $decimal at $hex: file .*/aarch64-lrcpc3.c, line $decimal\\." \
> +	"$name: break at prologue instruction"
> +
> +    # Record the initial memory and register values.
> +    set regs [concat $diff_reg $same_reg]
> +    set vars [concat $diff_var $same_var]
> +    set mem [concat $diff_mem $same_mem]
> +    foreach r $regs {
> +	set ${r}_initial [capture_command_output "info register $r" ""]
> +    }
> +    foreach v $vars {
> +	set ${v}_initial [get_valueof "/x" "$v" "unable to read $v" \
> +	    "$name: get $v initial value"]
> +    }
> +    foreach m $mem {
> +	set ${m}_initial [capture_command_output "x/x $m" ""]
> +    }
> +
> +    gdb_test "break $after_seq" \
> +	"Breakpoint $decimal at $hex: file .*/aarch64-lrcpc3.c, line $decimal\\." \
> +	"$name: break after instruction sequence"
> +    gdb_continue_to_breakpoint "$name: executed instruction sequence" \
> +	[multi_line ".*/aarch64-lrcpc3.c:$decimal" ".*"]
> +
> +    # Record the new memory and register values.
> +    foreach r $regs {
> +	set ${r}_new [capture_command_output "info register $r" ""]
> +    }
> +    foreach v $vars {
> +	set ${v}_new [get_valueof "/x" "$v" "unable to read $v" \
> +	    "$name: get $v new value"]
> +    }
> +    foreach m $mem {
> +	set ${m}_new [capture_command_output "x/x $m" ""]
> +    }
> +
> +    # Execute in reverse to before the instruction sequence.
> +    gdb_test_no_output "set exec-direction reverse"
> +
> +    gdb_continue_to_breakpoint "reversed execution of instruction sequence" \
> +	[multi_line ".*/aarch64-lrcpc3.c:$decimal" \
> +	    "$decimal\[ \t\]+__asm__ volatile \\(\"${insn} \[^\r\n\]+\""]
> +
> +    # Record the final memory and register values.
> +    foreach r $regs {
> +	set ${r}_final [capture_command_output "info register $r" ""]
> +    }
> +    foreach v $vars {
> +	set ${v}_final [get_valueof "/x" "$v" "unable to read $v" \
> +	    "$name: get $v final value"]
> +    }
> +    foreach m $mem {
> +	set ${m}_final [capture_command_output "x/x $m" ""]
> +    }
> +
> +    foreach v [concat $same_reg $same_var $same_mem] {
> +	gdb_assert ![string compare [set ${v}_initial] [set ${v}_new]] \
> +	    "$name: check $v initial value versus $v new value"
> +	gdb_assert ![string compare [set ${v}_initial] [set ${v}_final]] \
> +	    "$name: check $v initial value versus $v final value"
> +    }
> +
> +    foreach v [concat $diff_reg $diff_var $diff_mem] {
> +	gdb_assert [string compare [set ${v}_initial] [set ${v}_new]] \
> +	    "$name: check $v initial value versus $v new value"
> +	gdb_assert ![string compare [set ${v}_initial] [set ${v}_final]] \
> +	    "$name: check $v initial value versus $v final value"
> +    }
> +
> +    # Restore forward execution and go to end of recording.
> +    gdb_test_no_output "set exec-direction forward"
> +    gdb_test "record goto end" \
> +	[multi_line \
> +	    "Go forward to insn number $decimal" \
> +	    "#0  main \\(\\) at .*/aarch64-lrcpc3.c:$decimal" \
> +	    ".*"]
> +}
> +
> +set ldiapp_cases {
> +	{ ldiapp-0 { x19 x20 } {     } { } { } { ptr } { src } }
> +	{ ldiapp-1 { w19 w20 } {     } { } { } { ptr } { src } }
> +	{ ldiapp-2 { x19 x20 } { ptr } { } { } {     } { src } }
> +	{ ldiapp-3 { w19 w20 } { ptr } { } { } {     } { src } }
> +	{ ldiapp-4 { x21 x20 } {     } { } { } {     } { src } }
> +	{ ldiapp-5 { w21 w20 } {     } { } { } {     } { src } }
> +}
> +
> +set stilp_cases {
> +	{ stilp-0  { } {     } { src } { x19 x20 } { ptr } { } }
> +	{ stilp-1  { } {     } { src } { w19 w20 } { ptr } { } }
> +	{ stilp-2  { } { ptr } { src } { x19 x20 } {     } { } }
> +	{ stilp-3  { } { ptr } { src } { x19 x20 } {     } { } }
> +	{ stilp-4  { } {     } { src } { x20     } { ptr } { } }
> +	{ stilp-5  { } {     } { src } { w20     } { ptr } { } }
> +}
> +
> +set ldapr_stlr_cases {
> +	{ ldapr-0  { x19 } { ptr } {     } {     } { } { src } }
> +	{ ldapr-1  { w19 } { ptr } {     } {     } { } { src } }
> +	{ stlr-0   {     } { ptr } { src } { x19 } { } {     } }
> +	{ stlr-1   {     } { ptr } { src } { w19 } { } {     } }
> +}
> +
> +set ldap1_stl1_cases {
> +	{ ldap1-0  { v22 } { } {     } { ptr } { } { src } }
> +	{ stl1-0   {     } { } { src } { v22 } { } {     } }
> +}
> +
> +set ldapur_stlur_cases {
> +	{ ldapur-0 { v22 } { } {     } { ptr } {     } { src } }
> +	{ stlur-0  {     } { } { src } { v22 } { ptr } {     } }
> +	{ ldapur-1 { v22 } { } {     } { ptr } {     } { src } }
> +	{ stlur-1  {     } { } { src } { v22 } { ptr } {     } }
> +	{ ldapur-2 { v22 } { } {     } { ptr } {     } { src } }
> +	{ stlur-2  {     } { } { src } { v22 } { ptr } {     } }
> +	{ ldapur-3 { v22 } { } {     } { ptr } {     } { src } }
> +	{ stlur-3  {     } { } { src } { v22 } { ptr } {     } }
> +	{ ldapur-4 { v22 } { } {     } { ptr } {     } { src } }
> +	{ stlur-4  {     } { } { src } { v22 } { ptr } {     } }
> +	{ ldapur-5 { v22 } { } {     } { ptr } {     } { src } }
> +	{ stlur-5  {     } { } { src } { v22 } { ptr } {     } }
> +	{ ldapur-6 { v22 } { } {     } { ptr } {     } { src } }
> +	{ stlur-6  {     } { } { src } { v22 } { ptr } {     } }
> +}
> +
> +set all_cases [concat \
> +    $ldiapp_cases $stilp_cases $ldapr_stlr_cases \
> +    $ldap1_stl1_cases $ldapur_stlur_cases]
> +
> +foreach c $all_cases {
> +    lassign $c name diff_reg diff_var diff_mem same_reg same_var same_mem
> +    test_single_asm $name $diff_reg $diff_var $diff_mem $same_reg $same_var $same_mem
> +}
> diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> index 28709004570..c6afc556548 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -5287,6 +5287,69 @@ gdb_caching_proc allow_aarch64_fpmr_tests {} {
>       return $allow_fpmr_tests
>   }
>   
> +# Run a test on the target to see if it supports AArch64 LRCPC3 (Load-Acquire
> +# RCpc instructions) extensions.  Return 1 if so, 0 if it does not.  Note this
> +# causes a restart of GDB.
> +
> +gdb_caching_proc allow_aarch64_lrcpc3_tests {} {
> +    global srcdir subdir gdb_prompt inferior_exited_re
> +
> +    set me "allow_aarch64_lrcpc3_tests"
> +
> +    if { ![is_aarch64_target] } {
> +	return 0
> +    }
> +
> +    # Take the opportunity to check whether the toolchain knows about LRCPC3.
> +    set compile_flags "{additional_flags=-march=armv8-a+rcpc3}"
> +
> +    # Compile a program that tests the LRCPC3 feature.
> +    set src {
> +    #include <stdint.h>
> +
> +    int main() {
> +	  uint64_t a, b = 0;
> +	  uint64_t *ptr;
> +	  *ptr = 0xdeadbeef;
> +
> +	  __asm__ volatile ("ldiapp %0, %1, [%2]\n"
> +	    : "=r"(a), "=r"(b)
> +	    : "r"(ptr)
> +	    : "memory");
> +
> +	  return 0;
> +	}
> +    }
> +
> +    if {![gdb_simple_compile $me $src executable $compile_flags]} {
> +	return 0
> +    }
> +
> +    # Compilation succeeded so now run it via gdb.
> +    clean_restart
> +    gdb_load $obj
> +    gdb_run_cmd
> +    gdb_expect {
> +	-re ".*Illegal instruction.*${gdb_prompt} $" {
> +	    verbose -log "\n$me lrcpc3 support not detected"
> +	    set allow_lrcpc3_tests 0
> +	}
> +	-re ".*$inferior_exited_re normally.*${gdb_prompt} $" {
> +	    verbose -log "\n$me: lrcpc3 support detected"
> +	    set allow_lrcpc3_tests 1
> +	}
> +	default {
> +	  warning "\n$me: default case taken"
> +	    set allow_lrcpc3_tests 0
> +	}
> +    }
> +    gdb_exit
> +    remote_file build delete $obj
> +
> +    verbose "$me:  returning $allow_lrcpc3_tests" 2
> +    return $allow_lrcpc3_tests
> +}
> +
>   # Run a test on the target to see if it supports AArch64 MOPS (Memory
>   # Operations) extensions.  Return 1 if so, 0 if it does not.  Note this
>   # causes a restart of GDB.


-- 
Cheers,
Guinevere Larsen
It/she


  parent reply	other threads:[~2026-04-24 15:10 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-20 21:52 [PATCH 0/4] gdb/aarch64: record/replay support for AArch64 Ezra.Sitorus
2026-04-20 21:52 ` [PATCH 1/4] gdb/aarch64: record/replay support for LRCPC3 Ezra.Sitorus
2026-04-24  7:00   ` Luis
2026-04-24 15:09   ` Guinevere Larsen [this message]
2026-04-25  5:08   ` Thiago Jung Bauermann
2026-04-25  7:21   ` Thiago Jung Bauermann
2026-04-20 21:52 ` [PATCH 2/4] gdb/aarch64: Test record/replay support for CSSC Ezra.Sitorus
2026-04-24  7:07   ` Luis
2026-04-24 16:53   ` Guinevere Larsen
2026-04-25  6:10   ` Thiago Jung Bauermann
2026-04-25  7:28   ` Thiago Jung Bauermann
2026-04-20 21:52 ` [PATCH 3/4] gdb/aarch64: record/replay support for RPRFM and PRFM (reg) Ezra.Sitorus
2026-04-24  7:08   ` Luis
2026-04-24 16:56   ` Guinevere Larsen
2026-04-25  8:12   ` Thiago Jung Bauermann
2026-04-20 21:52 ` [PATCH 4/4] gdb/aarch64: record/replay support for LSE128 Ezra.Sitorus
2026-04-24  7:11   ` Luis
2026-04-24 17:12   ` Guinevere Larsen
2026-04-25  8:38   ` Thiago Jung Bauermann
2026-04-23 17:31 ` [PATCH 0/4] gdb/aarch64: record/replay support for AArch64 Guinevere Larsen
2026-04-23 22:20   ` Ezra Sitorus
2026-04-24  5:33   ` Thiago Jung Bauermann
2026-04-24  7:16 ` Luis

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=76af2403-c565-418d-b730-10b0490565db@redhat.com \
    --to=guinevere@redhat.com \
    --cc=Ezra.Sitorus@arm.com \
    --cc=gdb-patches@sourceware.org \
    --cc=luis.machado.foss@gmail.com \
    --cc=thiago.bauermann@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox