From patchwork Thu May 23 03:51:23 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Thiago Jung Bauermann X-Patchwork-Id: 798394 Delivered-To: patch@linaro.org Received: by 2002:a5d:6a47:0:b0:354:fb4b:99cd with SMTP id t7csp28950wrw; Wed, 22 May 2024 20:52:06 -0700 (PDT) X-Forwarded-Encrypted: i=3; AJvYcCWNweTYcQbX6F+TqQknRQscPpkwyHKd+0CUbeZYLSDFZuDP49W1mI69mDhF62fWd9ksZZVSNlUuDdz+QhDOEC9L X-Google-Smtp-Source: AGHT+IHo1MjLkcrmLlmosX5jYxO9X2sFo0JyXYcbBvoSi+ncR1BbKh/8Hy/kFp5FAyyu6YCy8y4t X-Received: by 2002:aca:130b:0:b0:3c9:6a50:95f5 with SMTP id 5614622812f47-3cdb949ab4dmr3565015b6e.56.1716436326411; Wed, 22 May 2024 20:52:06 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1716436326; cv=pass; d=google.com; s=arc-20160816; b=zNkOyDCyGw490Riv/6Dr7T3OpPobiyPASHgKJPd9R2F9bWM22h9Rz9Dr6xKWOBglyM cMdNd2aPHlir61lpSJgciIXrKC20gPX85oLCHk3985h8wKTP+UQ+sS7wTvPw9r8EFgfP DIZK6JfvmcxqzUCJCz8vuRcoppSINrfmBZQ9+g2TWv6vyCR9obtg/IA7EP7DWY1Y7L8/ fucg8sX7GbulwYKbAwAUbDsKP8pmzC5/IXK/CukKxH0xsgMt4MeoCse0cRkHr75wmOyj Mm6vIXMB3CPr3YBW+x08Y+tAnCY3c/VHRzMrLUyf0abl8lG3TG3J+oTdxSyosHsFL4vj eOIA== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; 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:arc-filter:dmarc-filter:delivered-to; bh=zVNfO5kmVGXfUFvfwlVZxOEUsGM9F8bYwhPy68tk7b0=; fh=loWCTN49GeJC1HCrrvtQFeZ0kzyLaMXCA7ZZRe9+Kj4=; b=hrHQRvyKXnP+ayZ3hM9B6wWtgGgiTDBfMWehnWV4dTJVEMyh7/dN9XfmQYTMQYVcKT 6YuD7H9txoOfMmQAq5/PShsja8AQqh6exL50wJ63Ej5DIKs5ScIZrNHFHAo9kR/rSR1r V079Zu4c5vDbHrfxX+7Dq7K2AgQm6RJ4RCRW2/i4nwSYDiOZkwSQzhmKHSf6AXNWkI/l jcyMBYUo+AyFgLr0L/F4SzdvxRRv9DKMD1snEPazHaHGofd54K6mbVznCmu4Lg7jSEp/ 8AhrHFdQaqy8tqfK4h0qxMD0F8ufDJv5jyi2fPOPhr8jCec6Zm+G02TFonk35s0HLDFf XEmQ==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=ndeSTW1X; arc=pass (i=1); spf=pass (google.com: domain of gdb-patches-bounces+patch=linaro.org@sourceware.org designates 8.43.85.97 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. [8.43.85.97]) by mx.google.com with ESMTPS id af79cd13be357-792bf29aa05si734767385a.224.2024.05.22.20.52.06 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 22 May 2024 20:52:06 -0700 (PDT) Received-SPF: pass (google.com: domain of gdb-patches-bounces+patch=linaro.org@sourceware.org designates 8.43.85.97 as permitted sender) client-ip=8.43.85.97; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=ndeSTW1X; arc=pass (i=1); spf=pass (google.com: domain of gdb-patches-bounces+patch=linaro.org@sourceware.org designates 8.43.85.97 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 E05363858C62 for ; Thu, 23 May 2024 03:52:05 +0000 (GMT) X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mail-io1-xd2d.google.com (mail-io1-xd2d.google.com [IPv6:2607:f8b0:4864:20::d2d]) by sourceware.org (Postfix) with ESMTPS id 699AF384F4B9 for ; Thu, 23 May 2024 03:51:36 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 699AF384F4B9 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 699AF384F4B9 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::d2d ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1716436300; cv=none; b=LC5VdEpu9W2jTWqJSXMYt4s6wMiRv4VBCL4zKTpuS2ExF725td3+FfD1afMgJjaXo9jDhE7lCgRYvKYOJ4qaHDI4ZSsPTU3PHxqRETfjBFsy9s0FH1tOKkaVlqfjQ55TQkfEsp7PLwsoNnYGrEMSQcIJw26enfBfSE22pKcEGSU= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1716436300; c=relaxed/simple; bh=swY4W75GePSKUuJ1t7QMB3M8dJhMmfTTrnlIEF6LYBo=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=Q5YkhGXvyV/soHXWaxQTbz9MarLNIvf5ArDMOor/xsheLnuLTQrwy/QQIcFrvCHkOZ1CjpM7Q4i9x08fud53xet/XI3bni9cpnvP4RfbHXV83u3eQYVGSVNG67zT3U5H1QjzFpEhtQIDiyk0iTs8RTA08vBc70tLXhrXx7PFaxw= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-io1-xd2d.google.com with SMTP id ca18e2360f4ac-7e2119a1b82so205129039f.0 for ; Wed, 22 May 2024 20:51:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1716436295; x=1717041095; 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=zVNfO5kmVGXfUFvfwlVZxOEUsGM9F8bYwhPy68tk7b0=; b=ndeSTW1XnzwQJbaLPXgndRriJTsfHtXqzN9ZbC96Au6LT5er5BDqrbzNyWk4oab8Kb vlME3cYyiDa3V16DsfAX1lJVOkRxLZ5hRLI+ptc4ZRAJOVfSoF0J0IvtMEtFfjN6Hkcf /HqTr231x1EmWSjtKpxeXeHxqwUNsEycK6jUtCCBORRQ8sozfXhXLqOcRSfq9nqQMu/c zodaBOl5C2eWEbWS3G5GOsHCX8k/979btejQxtuTGZ51C1QDz/0W2EV3GWgx2cGdSen/ sy/aC6P3THJ380nVh92szZaonUK9HJ5m60mC+n3L8SxDTZUIVPMJXcWS4KAtlt/Iqz3y BuSQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1716436295; x=1717041095; 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=zVNfO5kmVGXfUFvfwlVZxOEUsGM9F8bYwhPy68tk7b0=; b=vgpG0judOM4wlVNrYyWB0LqZ5ba6o4UuG1N/AsQ1iVL6qZ/lq/9jRQhLhA0tc4zpXy ej2ZmR4ZKWQfDrg1XF7cnplyHPgppE+EPfexIZ9tFveTsPV/cTkF9GiZEvFAblv8RH5E VzSq3jDCqa+zGNbtDbdBOV8JuD0FeWtLOAvyx5G1Q1KXvFJ0Eygs6c7zqN3RjRpOqT3n CkLMrGiUBA9fyMys9mJw6ic6OUCY3UtONskwaob3r+cZB80LXvyx6OyZIeHN1LO7r7MV FnltIpQH/V+icK56DzjKghKFGFS8hB7uKw2ZrPcyJAQPNlpRjADW6Nn91hak8Y/SAgqN yg1w== X-Gm-Message-State: AOJu0YxxqfYX/xt78Frf5olLwRAOZU1jFUz3kTUjcqaYiSdM8JIB+71D 0ecRmUGzxnNyUxACx3AWTUx0dfRKu49PptXrG0lEEJ1uIbq7o/65mPpzaEtLLJhrzIoMNgOomep w X-Received: by 2002:a92:ca4d:0:b0:36c:c5ef:8265 with SMTP id e9e14a558f8ab-371f3f481f2mr42980935ab.0.1716436295407; Wed, 22 May 2024 20:51:35 -0700 (PDT) Received: from localhost ([2804:14d:7e39:8470:f149:d562:aa25:4733]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-6f67ed10e79sm11886134b3a.45.2024.05.22.20.51.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 22 May 2024 20:51:35 -0700 (PDT) From: Thiago Jung Bauermann To: gdb-patches@sourceware.org Cc: Christophe Lyon , Luis Machado , Guinevere Larsen , Pedro Alves Subject: [PATCH v4 2/3] gdb/aarch64: Add record support for MOPS instructions. Date: Thu, 23 May 2024 00:51:23 -0300 Message-ID: <20240523035124.2639220-3-thiago.bauermann@linaro.org> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20240523035124.2639220-1-thiago.bauermann@linaro.org> References: <20240523035124.2639220-1-thiago.bauermann@linaro.org> MIME-Version: 1.0 X-Spam-Status: No, score=-10.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org 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 There are two kinds of MOPS instructions: set instructions and copy instructions. Within each group there are variants with minor differences in how they read or write to memory — e.g., non-temporal read and/or write, unprivileged read and/or write and permutations of those — but they work in the same way in terms of the registers and regions of memory that they modify. The new gdb.reverse/aarch64-mops.exp testcase verifies that MOPS instructions are recorded and correctly reversed. Not all variants of the copy and set instructions are tested, since there are many and the record and replay target processes them in the same way. PR tdep/31666 Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31666 --- Changes in v4: - Implemented common path for set and copy instructions in aarch64_record_memcopy_memset (Suggested by Luis). - Removed identical or operands in aarch64_record_memcopy_memset. - Moved gdb.reverse/aarch64-mops.exp testcase to this patch (Suggested by Guinevere). - Use foreach_with_prefix instead of test procedure in testcase (Suggested by Guinevere). - Use gdb_continue_to_breakpoint instead of gdb_test "continue" in testcase (Suggested by Guinevere). - Test that source and dest variables are correctly recorded. - Reset dest variable after each memops sequence. - Step to prologue instruction after hitting "before" breakpoint and put a breakpoint there, to cope with Clang's line number info including some register preparation instructions as part of the line with the asm statement. No change in v1, v2 or v3. gdb/aarch64-tdep.c | 69 ++++++++ gdb/testsuite/gdb.reverse/aarch64-mops.c | 78 +++++++++ gdb/testsuite/gdb.reverse/aarch64-mops.exp | 186 +++++++++++++++++++++ 3 files changed, 333 insertions(+) create mode 100644 gdb/testsuite/gdb.reverse/aarch64-mops.c create mode 100644 gdb/testsuite/gdb.reverse/aarch64-mops.exp diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c index 05ecd421cd0e..8b7582d12be9 100644 --- a/gdb/aarch64-tdep.c +++ b/gdb/aarch64-tdep.c @@ -5188,6 +5188,71 @@ aarch64_record_asimd_load_store (aarch64_insn_decode_record *aarch64_insn_r) return AARCH64_RECORD_SUCCESS; } +/* Record handler for Memory Copy and Memory Set instructions. */ + +static unsigned int +aarch64_record_memcopy_memset (aarch64_insn_decode_record *aarch64_insn_r) +{ + if (record_debug) + debug_printf ("Process record: memory copy and memory set\n"); + + uint8_t op1 = bits (aarch64_insn_r->aarch64_insn, 22, 23); + uint8_t op2 = bits (aarch64_insn_r->aarch64_insn, 12, 15); + uint32_t reg_rd = bits (aarch64_insn_r->aarch64_insn, 0, 4); + uint32_t reg_rn = bits (aarch64_insn_r->aarch64_insn, 5, 9); + uint32_t record_buf[3]; + uint64_t record_buf_mem[4]; + + if (op1 == 3 && op2 > 11) + /* Unallocated instructions. */ + return AARCH64_RECORD_UNKNOWN; + + /* Set instructions have two registers and one memory region to be + recorded. */ + record_buf[0] = reg_rd; + record_buf[1] = reg_rn; + aarch64_insn_r->reg_rec_count = 2; + + ULONGEST dest_addr; + regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rd, &dest_addr); + + LONGEST length; + regcache_raw_read_signed (aarch64_insn_r->regcache, reg_rn, &length); + + /* In one ofthe algorithm options a processor can implement, the length + in Rn has an inverted sign. */ + if (length < 0) + length *= -1; + + record_buf_mem[0] = length; + record_buf_mem[1] = dest_addr; + aarch64_insn_r->mem_rec_count = 1; + + if (op1 != 3) + { + /* Copy instructions have an additional register and an additional + memory region to be recorded. */ + uint32_t reg_rs = bits (aarch64_insn_r->aarch64_insn, 16, 20); + + record_buf[2] = reg_rs; + aarch64_insn_r->reg_rec_count++; + + ULONGEST source_addr; + regcache_raw_read_unsigned (aarch64_insn_r->regcache, reg_rs, + &source_addr); + + record_buf_mem[2] = length; + record_buf_mem[3] = source_addr; + aarch64_insn_r->mem_rec_count++; + } + + MEM_ALLOC (aarch64_insn_r->aarch64_mems, aarch64_insn_r->mem_rec_count, + record_buf_mem); + REG_ALLOC (aarch64_insn_r->aarch64_regs, aarch64_insn_r->reg_rec_count, + record_buf); + return AARCH64_RECORD_SUCCESS; +} + /* Record handler for load and store instructions. */ static unsigned int @@ -5465,6 +5530,10 @@ aarch64_record_load_store (aarch64_insn_decode_record *aarch64_insn_r) if (insn_bits10_11 == 0x01 || insn_bits10_11 == 0x03) record_buf[aarch64_insn_r->reg_rec_count++] = reg_rn; } + /* Memory Copy and Memory Set instructions. */ + else if ((insn_bits24_27 & 1) == 1 && insn_bits28_29 == 1 + && insn_bits10_11 == 1 && !insn_bit21) + return aarch64_record_memcopy_memset (aarch64_insn_r); /* Advanced SIMD load/store instructions. */ else return aarch64_record_asimd_load_store (aarch64_insn_r); diff --git a/gdb/testsuite/gdb.reverse/aarch64-mops.c b/gdb/testsuite/gdb.reverse/aarch64-mops.c new file mode 100644 index 000000000000..95318fed9d93 --- /dev/null +++ b/gdb/testsuite/gdb.reverse/aarch64-mops.c @@ -0,0 +1,78 @@ +/* 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 + +#define INITIAL_STRING "Initial fill value." +#define NEW_STRING "Just a test string." +#define BUF_SIZE sizeof(NEW_STRING) + +int +main (void) +{ + char dest[BUF_SIZE] = INITIAL_STRING; + char source[BUF_SIZE] = NEW_STRING; + register char *p asm ("x19"); + register char *q asm ("x20"); + register long size asm ("x21"); + register long zero asm ("x22"); + + p = dest; + size = BUF_SIZE; + zero = 0; + /* Before setp. */ + /* memset implemented in MOPS instructions. */ + __asm__ volatile ("setp [%0]!, %1!, %2\n\t" + "setm [%0]!, %1!, %2\n\t" + "sete [%0]!, %1!, %2\n\t" + : "+&r"(p), "+&r"(size) + : "r"(zero) + : "memory"); + + /* After sete. */ + p = dest; + q = source; + size = BUF_SIZE; + memcpy (dest, INITIAL_STRING, sizeof (dest)); + /* Before cpyp. */ + /* memmove implemented in MOPS instructions. */ + __asm__ volatile ("cpyp [%0]!, [%1]!, %2!\n\t" + "cpym [%0]!, [%1]!, %2!\n\t" + "cpye [%0]!, [%1]!, %2!\n\t" + : "+&r" (p), "+&r" (q), "+&r" (size) + : + : "memory"); + + /* After cpye. */ + p = dest; + q = source; + size = BUF_SIZE; + memcpy (dest, INITIAL_STRING, sizeof (dest)); + /* Before cpyfp. */ + /* memcpy implemented in MOPS instructions. */ + __asm__ volatile ("cpyfp [%0]!, [%1]!, %2!\n\t" + "cpyfm [%0]!, [%1]!, %2!\n\t" + "cpyfe [%0]!, [%1]!, %2!\n\t" + : "+&r" (p), "+&r" (q), "+&r" (size) + : + : "memory"); + + /* After cpyfe. */ + p = dest; + + return 0; +} diff --git a/gdb/testsuite/gdb.reverse/aarch64-mops.exp b/gdb/testsuite/gdb.reverse/aarch64-mops.exp new file mode 100644 index 000000000000..05a991d4bfb9 --- /dev/null +++ b/gdb/testsuite/gdb.reverse/aarch64-mops.exp @@ -0,0 +1,186 @@ +# 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 instruction record for AArch64 FEAT_MOPS instructions. +# Based on gdb.reverse/ppc_record_test_isa_3_1.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_mops_tests + +standard_testfile + +if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \ + [list debug additional_flags=-march=armv9.3-a]] } { + return -1 +} + +if ![runto_main] { + return -1 +} + +gdb_test_no_output "record full" + +foreach_with_prefix insn_prefix {"set" "cpy" "cpyf"} { + global decimal hex + + set before_seq [gdb_get_line_number "Before ${insn_prefix}p"] + set after_seq [gdb_get_line_number "After ${insn_prefix}e"] + + gdb_test "break $before_seq" \ + "Breakpoint $decimal at $hex: file .*/aarch64-mops.c, line $decimal\\." \ + "break before instruction sequence" + gdb_continue_to_breakpoint "about to execute instruction sequence" \ + [multi_line ".*/aarch64-mops.c:$decimal" \ + "$decimal\[ \t\]+__asm__ volatile \\(\"${insn_prefix}p \[^\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_prefix}p" + # Add a breakpoint that we're sure is at the prologue instruction. + gdb_test "break *\$pc" \ + "Breakpoint $decimal at $hex: file .*/aarch64-mops.c, line $decimal\\." \ + "break at prologue instruction" + + # Record the initial memory and register values. + set dest_initial [get_valueof "/x" "dest" "unable to read initial" \ + "get dest initial value"] + set x19_initial [capture_command_output "info register x19" ""] + set x21_initial [capture_command_output "info register x21" ""] + + # The set instructions use the ZERO variable, but not Q nor SOURCE, + # and the other instructions are the opposite. + if {[string compare $insn_prefix "set"] == 0} { + set x22_initial [capture_command_output "info register x22" ""] + } else { + set x20_initial [capture_command_output "info register x20" ""] + set source_initial [get_valueof "/x" "source" "unable to read initial" \ + "get source initial value"] + } + + gdb_test "break $after_seq" \ + "Breakpoint $decimal at $hex: file .*/aarch64-mops.c, line $decimal\\." \ + "break after instruction sequence" + gdb_continue_to_breakpoint "executed instruction sequence" \ + [multi_line ".*/aarch64-mops.c:$decimal" "$decimal\[ \t\]+p = dest;"] + + # Record the new memory and register values. + set dest_new [get_valueof "/x" "dest" "unable to read new" \ + "get dest new value"] + set x19_new [capture_command_output "info register x19" ""] + set x21_new [capture_command_output "info register x21" ""] + + if {[string compare $insn_prefix "set"] == 0} { + set x22_new [capture_command_output "info register x22" ""] + } else { + set x20_new [capture_command_output "info register x20" ""] + set source_new [get_valueof "/x" "source" "unable to read new" \ + "get source new value"] + } + + # 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-mops.c:$decimal" \ + "$decimal\[ \t\]+__asm__ volatile \\(\"${insn_prefix}p \[^\r\n\]+\""] + + # Record the final memory and register values. + set dest_final [get_valueof "/x" "dest" "unable to read final" \ + "get dest final value"] + set x19_final [capture_command_output "info register x19" ""] + set x21_final [capture_command_output "info register x21" ""] + + if {[string compare $insn_prefix "set"] == 0} { + set x22_final [capture_command_output "info register x22" ""] + } else { + set x20_final [capture_command_output "info register x20" ""] + set source_final [get_valueof "/x" "source" "unable to read final" \ + "get source final value"] + } + + # Check initial and new values of dest are different. + gdb_assert [string compare $dest_initial $dest_new] \ + "check dest initial value versus dest new value" + + # Check initial and new values of x19 are different. + gdb_assert [string compare $x19_initial $x19_new] \ + "check x19 initial value versus x19 new value" + + # Check initial and new values of x21 are different. + gdb_assert [string compare $x21_initial $x21_new] \ + "check x21 initial value versus x21 new value" + + if {[string compare $insn_prefix "set"] == 0} { + # Check initial and new values of x22 are the same. + # The register with the value to set shouldn't change. + gdb_assert ![string compare $x22_initial $x22_new] \ + "check x22 initial value versus x22 new value" + } else { + # Check initial and new values of x20 are different. + gdb_assert [string compare $x20_initial $x20_new] \ + "check x20 initial value versus x20 new value" + # Check initial and new values of source are the same. + gdb_assert ![string compare $source_initial $source_new] \ + "check source initial value versus source new value" + } + + # Check initial and final values of dest are the same. + gdb_assert ![string compare $dest_initial $dest_final] \ + "check dest initial value versus dest final value" + + # Check initial and final values of x19 are the same. + gdb_assert ![string compare $x19_initial $x19_final] \ + "check x19 initial value versus x19 final value" + + # Check initial and final values of x21 are the same. + gdb_assert ![string compare $x21_initial $x21_final] \ + "check x21 initial value versus x21 final value" + + if {[string compare $insn_prefix "set"] == 0} { + # Check initial and final values of x22 are the same. + gdb_assert ![string compare $x22_initial $x22_final] \ + "check x22 initial value versus x22 final value" + } else { + # Check initial and final values of x20 are the same. + gdb_assert ![string compare $x20_initial $x20_final] \ + "check x20 initial value versus x20 final value" + + # Check initial and final values of source are the same. + gdb_assert ![string compare $source_initial $source_final] \ + "check source initial value versus source 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-mops.c:$decimal" \ + "$decimal\[ \t\]+p = dest;"] +}