Re: [PATCH v3 24/24] Add memory tagging testcases

David Spickett via Gdb-patches
2020-11-16T15:47:22Z

(I've just skimmed through so not a review in any real way)

In gdb/testsuite/gdb.arch/aarch64-mte.exp:
+# Test a binary with address signing works regardless of whether the target
+# supports pauth instructions. On non pauth systems, all pauth instructions
+# are treated as nops.

I assume this was left over from the original test file you adapted,
it doesn't apply to MTE.

On Mon, 9 Nov 2020 at 17:05, Luis Machado <luis.machado@linaro.org> wrote:
>
> Add an AArch64-specific test and a more generic memory tagging test that
> other architectures can run.
>
> Even though architectures not supporting memory tagging can run the memory
> tagging tests, the runtime check will make the tests bail out early, as it
> would make no sense to proceed without proper support.
>
> It is also tricky to do any further runtime tests for memory tagging, given
> we'd need to deal with tags, and those are arch-specific. Therefore the
> test in gdb.base is more of a smoke test.
>
> If an architecture wants to implement memory tagging, then it makes sense to
> have tests within gdb.arch instead.
>
> gdb/testsuite/ChangeLog:
>
> YYYY-MM-DD Luis Machado <luis.machado@linaro.org>
>
> * gdb.arch/aarch64-mte.c: New file.
> * gdb.arch/aarch64-mte.exp: New test.
> * gdb.base/memtag.c: New file.
> * gdb.base/memtag.exp: New test.
> * lib/gdb.exp (supports_memtag): New function.
> ---
> gdb/testsuite/gdb.arch/aarch64-mte.c | 107 +++++++
> gdb/testsuite/gdb.arch/aarch64-mte.exp | 371 +++++++++++++++++++++++++
> gdb/testsuite/gdb.base/memtag.c | 22 ++
> gdb/testsuite/gdb.base/memtag.exp | 64 +++++
> gdb/testsuite/lib/gdb.exp | 16 ++
> 5 files changed, 580 insertions(+)
> create mode 100644 gdb/testsuite/gdb.arch/aarch64-mte.c
> create mode 100644 gdb/testsuite/gdb.arch/aarch64-mte.exp
> create mode 100644 gdb/testsuite/gdb.base/memtag.c
> create mode 100644 gdb/testsuite/gdb.base/memtag.exp
>
> diff --git a/gdb/testsuite/gdb.arch/aarch64-mte.c b/gdb/testsuite/gdb.arch/aarch64-mte.c
> new file mode 100644
> index 0000000000..f6fb4cca67
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/aarch64-mte.c
> @@ -0,0 +1,107 @@
> +/* This test program is part of GDB, the GNU debugger.
> +
> + Copyright 2020 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/>. */
> +
> +/* Exercise AArch64's Memory Tagging Extension with tagged pointers. */
> +
> +/* This test was based on the documentation for the AArch64 Memory Tagging
> + Extension from the Linux Kernel, found in the sources in
> + Documentation/arm64/memory-tagging-extension.rst. */
> +
> +#include <errno.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <sys/auxv.h>
> +#include <sys/mman.h>
> +#include <sys/prctl.h>
> +
> +/* From arch/arm64/include/uapi/asm/hwcap.h */
> +#define HWCAP2_MTE (1 << 18)
> +
> +/* From arch/arm64/include/uapi/asm/mman.h */
> +#define PROT_MTE 0x20
> +
> +/* From include/uapi/linux/prctl.h */
> +#define PR_SET_TAGGED_ADDR_CTRL 55
> +#define PR_GET_TAGGED_ADDR_CTRL 56
> +#define PR_TAGGED_ADDR_ENABLE (1UL << 0)
> +#define PR_MTE_TCF_SHIFT 1
> +#define PR_MTE_TCF_NONE (0UL << PR_MTE_TCF_SHIFT)
> +#define PR_MTE_TCF_SYNC (1UL << PR_MTE_TCF_SHIFT)
> +#define PR_MTE_TCF_ASYNC (2UL << PR_MTE_TCF_SHIFT)
> +#define PR_MTE_TCF_MASK (3UL << PR_MTE_TCF_SHIFT)
> +#define PR_MTE_TAG_SHIFT 3
> +#define PR_MTE_TAG_MASK (0xffffUL << PR_MTE_TAG_SHIFT)
> +
> +void
> +access_memory (unsigned char *tagged_ptr, unsigned char *untagged_ptr)
> +{
> + tagged_ptr[0] = 'a';
> +}
> +
> +int
> +main (int argc, char **argv)
> +{
> + unsigned char *tagged_ptr;
> + unsigned char *untagged_ptr;
> + unsigned long page_sz = sysconf (_SC_PAGESIZE);
> + unsigned long hwcap2 = getauxval(AT_HWCAP2);
> +
> + /* Bail out if MTE is not supported. */
> + if (!(hwcap2 & HWCAP2_MTE))
> + return 1;
> +
> + /* Enable the tagged address ABI, synchronous MTE tag check faults and
> + allow all non-zero tags in the randomly generated set. */
> + if (prctl (PR_SET_TAGGED_ADDR_CTRL,
> + PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_SYNC
> + | (0xfffe << PR_MTE_TAG_SHIFT),
> + 0, 0, 0))
> + {
> + perror ("prctl () failed");
> + return 1;
> + }
> +
> + /* Create a mapping that will have PROT_MTE set. */
> + tagged_ptr = mmap (0, page_sz, PROT_READ | PROT_WRITE,
> + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
> + if (tagged_ptr == MAP_FAILED)
> + {
> + perror ("mmap () failed");
> + return 1;
> + }
> +
> + /* Create another mapping that won't have PROT_MTE set. */
> + untagged_ptr = mmap (0, page_sz, PROT_READ | PROT_WRITE,
> + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
> + if (untagged_ptr == MAP_FAILED)
> + {
> + perror ("mmap () failed");
> + return 1;
> + }
> +
> + /* Enable MTE on the above anonymous mmap. */
> + if (mprotect (tagged_ptr, page_sz, PROT_READ | PROT_WRITE | PROT_MTE))
> + {
> + perror ("mprotect () failed");
> + return 1;
> + }
> +
> + access_memory (tagged_ptr, untagged_ptr);
> +
> + return 0;
> +}
> diff --git a/gdb/testsuite/gdb.arch/aarch64-mte.exp b/gdb/testsuite/gdb.arch/aarch64-mte.exp
> new file mode 100644
> index 0000000000..39dba493fb
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/aarch64-mte.exp
> @@ -0,0 +1,371 @@
> +# Copyright (C) 2020 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 a binary with address signing works regardless of whether the target
> +# supports pauth instructions. On non pauth systems, all pauth instructions
> +# are treated as nops.
> +
> +global hex
> +global decimal
> +
> +# Return TAG in hex format with no leading zeroes.
> +proc get_hex_tag { tag } {
> + return [format "%x" $tag]
> +}
> +
> +# Return TAG in the NN format where N is 4 bits of the byte.
> +proc get_tag_nn { tag } {
> + return [format "%02x" $tag]
> +}
> +
> +# Return the address of PTR with a tag of TAG.
> +proc get_tagged_ptr { tag ptr } {
> + set addr [get_hexadecimal_valueof $ptr -1]
> + return [get_valueof "/x" \
> + "${addr} & (0xf0ffffffffffffff) | ((unsigned long) ${tag} << 56)" \
> + "0" "fetch pointer ${ptr} with tag ${tag}"]
> +}
> +
> +# Return the logical TAG from PTR.
> +proc get_ltag_from_ptr { ptr } {
> + set addr [get_hexadecimal_valueof $ptr -1]
> + return [get_valueof "/x" "${addr} >> 56 & 0xf" -1 \
> + "fetch tag from pointer ${ptr}"]
> +}
> +
> +if {![is_aarch64_target]} {
> + verbose "Skipping ${gdb_test_file_name}."
> + return
> +}
> +
> +standard_testfile
> +if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } {
> + return -1
> +}
> +
> +if ![runto_main] {
> + untested "could not run to main"
> + return -1
> +}
> +
> +# Targets that don't support memory tagging should not execute the
> +# runtime memory tagging tests.
> +if {![supports_memtag]} {
> + untested "memory tagging unsupported"
> + return -1
> +}
> +
> +gdb_breakpoint "access_memory"
> +
> +if [gdb_continue "access_memory"] {
> + fail "could not run to tagged memory test function"
> + return -1
> +}
> +
> +# Fetch a known pointer to an area mapped with PROT_MTE.
> +set tagged_ptr_symbol "tagged_ptr"
> +set tagged_ptr_addr [get_hexadecimal_valueof $tagged_ptr_symbol -1]
> +
> +if {$tagged_ptr_addr == -1} {
> + untested "unexpected pointer or tag value"
> + return -1
> +}
> +
> +# Fetch a known pointer to an area not mapped with PROT_MTE.
> +set untagged_ptr_symbol "untagged_ptr"
> +set untagged_ptr_addr [get_hexadecimal_valueof $untagged_ptr_symbol -1]
> +
> +if {$untagged_ptr_addr == -1} {
> + untested "unexpected pointer or tag value"
> + return -1
> +}
> +
> +with_test_prefix "literals" {
> + # Test inspecting an allocation tag from a pointer to a memory area that
> + # is not mapped with PROT_MTE.
> + set msg "Address ${untagged_ptr_addr} not in a region mapped with a memory tagging flag\."
> + gdb_test "mtag showatag ${untagged_ptr_addr}" $msg \
> + "mtag showatag with an untagged address"
> +
> + gdb_test "mtag setatag ${untagged_ptr_addr} 0 00" $msg \
> + "mtag setatag with an untagged address"
> +
> + set addr_tagged 0
> + set addr_tagged_valid 0
> +
> + # Test setting and showing the logical tags for a literal address.
> + for {set i 0} {$i < 32} {incr i} {
> + with_test_prefix "tag ${i}" {
> + set addr_tagged [get_tagged_ptr $i ${tagged_ptr_addr}]
> + }
> +
> + set tag_hexnz [get_hex_tag [expr $i % 16]]
> + gdb_test "mtag showltag ${addr_tagged}" \
> + " = 0x${tag_hexnz}" \
> + "showltag with tag ${i}"
> +
> + set tag_hexnn [get_tag_nn $i]
> + gdb_test "mtag withltag ${addr_tagged} ${tag_hexnn}" \
> + " = \\(void \\*\\) ${addr_tagged}" \
> + "withltag with tag ${i}"
> + }
> +
> + set setatag_msg "Allocation tag\\(s\\) updated successfully\."
> + # Test setting and showing the allocation tags.
> + for {set i 0} {$i < 32} {incr i} {
> +
> + set tag_hexnn [get_tag_nn $i]
> + gdb_test "mtag setatag ${tagged_ptr_addr} 0 ${tag_hexnn}" \
> + $setatag_msg \
> + "setatag with tag ${i}"
> +
> + set tag_hexnz [get_hex_tag [expr $i % 16]]
> + gdb_test "mtag showatag ${tagged_ptr_addr}" " = 0x${tag_hexnz}" \
> + "showatag with tag ${i}"
> + }
> +
> + # Test tag mismatches.
> + with_test_prefix "tag mismatches" {
> + for {set i 0} {$i < 32} {incr i} {
> +
> + # Set the allocation tag to a known value.
> + set tag_hexnn [get_tag_nn $i]
> + gdb_test "mtag setatag ${tagged_ptr_addr} 0 ${tag_hexnn}" \
> + $setatag_msg \
> + "setatag with tag ${i}"
> +
> + set atag_hexnz [get_hex_tag [expr $i % 16]]
> +
> + # Validate that the logical tag matches the allocation tag.
> + with_test_prefix "tag ${i}" {
> + set addr_tagged [get_tagged_ptr $i ${tagged_ptr_addr}]
> + }
> +
> + gdb_test "mtag check ${addr_tagged}" \
> + "Memory tags for address $hex match \\(0x${atag_hexnz}\\)\." \
> + "check match with tag ${i}"
> +
> + # Get a pointer with the logical tag that does not match the
> + # allocation tag.
> + set ltag [expr $i + 1]
> + with_test_prefix "fetch mismatch tag ${i}" {
> + set addr_tagged [get_tagged_ptr $ltag ${tagged_ptr_addr}]
> + }
> +
> + # Validate that the logical tag does not match the allocation
> + # tag.
> + set ltag_hexnz [get_hex_tag [expr [expr $i + 1]% 16]]
> + gdb_test "mtag check ${addr_tagged}" \
> + "Logical tag \\(0x${ltag_hexnz}\\) does not match the allocation tag \\(0x${atag_hexnz}\\) for address $hex\." \
> + "check mismatch with tag ${i}"
> + }
> + }
> +}
> +
> +with_test_prefix "symbolic" {
> + # Test inspecting an allocation tag from a pointer to a memory area that
> + # is not mapped with PROT_MTE.
> + set msg "Address ${untagged_ptr_addr} not in a region mapped with a memory tagging flag\."
> + gdb_test "mtag showatag ${untagged_ptr_symbol}" $msg \
> + "mtag showatag with an untagged address"
> +
> + gdb_test "mtag setatag ${untagged_ptr_symbol} 0 00" $msg \
> + "mtag setatag with an untagged address"
> +
> + # Test setting and showing the logical tags for a literal address.
> + for {set i 0} {$i < 32} {incr i} {
> + set addr_tagged 0
> +
> + with_test_prefix "tag ${i}" {
> + set addr_tagged [get_tagged_ptr $i ${tagged_ptr_addr}]
> + gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${addr_tagged}" \
> + "update value of symbol ${tagged_ptr_symbol}"
> + }
> +
> + set tag_hexnz [get_hex_tag [expr $i % 16]]
> + gdb_test "mtag showltag ${tagged_ptr_symbol}" \
> + " = 0x${tag_hexnz}" \
> + "showltag with tag ${i}"
> +
> + set tag_hexnn [get_tag_nn $i]
> + gdb_test "mtag withltag ${tagged_ptr_symbol} ${tag_hexnn}" \
> + " = \\(void \\*\\) ${addr_tagged}" \
> + "withltag with tag ${i}"
> + }
> +
> + # Reset the tagged ptr to its original value
> + gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${tagged_ptr_addr}" \
> + "reset ${tagged_ptr_symbol} to ${tagged_ptr_addr}"
> +
> + set setatag_msg "Allocation tag\\(s\\) updated successfully\."
> + # Test setting and showing the allocation tags.
> + for {set i 0} {$i < 32} {incr i} {
> +
> + set tag_hexnn [get_tag_nn $i]
> + gdb_test "mtag setatag ${tagged_ptr_symbol} 0 ${tag_hexnn}" \
> + $setatag_msg \
> + "setatag with tag ${i}"
> +
> + set tag_hexnz [get_hex_tag [expr $i % 16]]
> + gdb_test "mtag showatag ${tagged_ptr_symbol}" " = 0x${tag_hexnz}" \
> + "showatag with tag ${i}"
> + }
> +
> + # Test tag mismatches.
> + with_test_prefix "tag mismatches" {
> + for {set i 0} {$i < 32} {incr i} {
> +
> + # Set the allocation tag to a known value (0).
> + set tag_hexnn [get_tag_nn $i]
> + gdb_test "mtag setatag ${tagged_ptr_symbol} 0 ${tag_hexnn}" \
> + $setatag_msg \
> + "setatag with tag ${i}"
> +
> + set atag_hexnz [get_hex_tag [expr $i % 16]]
> +
> + # Validate that the logical tag matches the allocation tag.
> + with_test_prefix "tag ${i}" {
> + set addr_tagged [get_tagged_ptr $i ${tagged_ptr_addr}]
> + }
> +
> + with_test_prefix "tag ${i}" {
> + gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${addr_tagged}" \
> + "set ${tagged_ptr_symbol} to a matching logical tag"
> + }
> +
> + gdb_test "mtag check ${tagged_ptr_symbol}" \
> + "Memory tags for address $hex match \\(0x${atag_hexnz}\\)\." \
> + "check match with tag ${i}"
> +
> + # Get a pointer with the logical tag that does not match the
> + # allocation tag.
> + set ltag [expr $i + 1]
> + with_test_prefix "fetch mismatch tag ${i}" {
> + set addr_tagged [get_tagged_ptr $ltag ${tagged_ptr_addr}]
> + }
> +
> + with_test_prefix "tag ${i}" {
> + gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${addr_tagged}" \
> + "set ${tagged_ptr_symbol} to a mismatching logical tag"
> + }
> +
> + # Validate that the logical tag does not match the allocation
> + # tag.
> + set ltag_hexnz [get_hex_tag [expr [expr $i + 1]% 16]]
> + gdb_test "mtag check ${tagged_ptr_symbol}" \
> + "Logical tag \\(0x${ltag_hexnz}\\) does not match the allocation tag \\(0x${atag_hexnz}\\) for address $hex\." \
> + "check mismatch with tag ${i}"
> + }
> + # Reset the tagged ptr to its original value
> + gdb_test_no_output "set variable ${tagged_ptr_symbol} = ${tagged_ptr_addr}" \
> + "reset ${tagged_ptr_symbol} to ${tagged_ptr_addr}"
> + }
> +}
> +
> +# Test the memory tagging extensions for the "print" command.
> +with_test_prefix "print command" {
> + set untagged_ptr [get_tagged_ptr 0 ${tagged_ptr_addr}]
> +
> + with_test_prefix "fetch ltag" {
> + set ltag [get_ltag_from_ptr ${tagged_ptr_addr}]
> + }
> +
> + if {$ltag == -1} {
> + untested "unexpected tag value"
> + return -1
> + }
> +
> + set atag [expr [expr $ltag + 1] % 16]
> + set atag_hexnn [get_tag_nn $atag]
> +
> + gdb_test "mtag setatag ${tagged_ptr_symbol} 0 ${atag_hexnn}" \
> + $setatag_msg \
> + "make atag and ltag different"
> +
> + set atag_hexnz [get_hex_tag $atag]
> + gdb_test "p/x ${tagged_ptr_symbol}" \
> + [multi_line \
> + "Logical tag \\(${ltag}\\) does not match the allocation tag \\(0x${atag_hexnz}\\)\." \
> + "\\\$\[0-9\]+ = ${untagged_ptr}"] \
> + "show tag mismatch"
> +}
> +
> +# Test the memory tagging extensions for the "x" command.
> +with_test_prefix "x command" {
> +
> + # Check if the allocation tags match what we expect.
> + gdb_test "x/gxm ${tagged_ptr_symbol}" \
> + [multi_line \
> + "<Allocation Tag $hex for range \\\[$hex,$hex\\)>" \
> + "$hex:\[ \t\]+$hex"] \
> + "outputs tag information"
> +
> + # Also make sure no tag information is output for memory areas without
> + # PROT_MTE mappings.
> + gdb_test "x/gxm ${untagged_ptr_symbol}" \
> + "$hex:\[ \t\]+$hex" \
> + "does not output tag information"
> +}
> +
> +# Validate the presence of the MTE registers.
> +foreach reg {"tag_ctl" } {
> + gdb_test "info registers $reg" \
> + "$reg\[ \t\]+$hex\[ \t\]+$decimal" \
> + "register $reg available"
> +}
> +
> +# Run until a crash and confirm GDB displays memory tag violation
> +# information.
> +gdb_test "continue" \
> + [multi_line \
> + "Program received signal SIGSEGV, Segmentation fault" \
> + "Memory tag violation while accessing address $hex" \
> + "Allocation tag $hex\." \
> + "$hex in access_memory \\(.*\\) at .*" \
> + ".*tagged_ptr\\\[0\\\] = 'a';"] \
> + "display tag violation information"
> +
> +# Restart to execute the async tag fault test.
> +with_test_prefix "async" {
> + if ![runto_main] {
> + untested "could not run to main"
> + return -1
> + }
> +
> + gdb_breakpoint "access_memory"
> +
> + if [gdb_continue "access_memory"] {
> + fail "could not run to tagged memory test function"
> + return -1
> + }
> +
> + # Force a tag fault.
> + gdb_test "mtag setatag tagged_ptr 0 05" \
> + $setatag_msg \
> + "make atag and ltag different"
> +
> + # Force the tag fault to be async.
> + gdb_test_no_output "set \$tag_ctl=0x7fff5" "set tag_ctl to async"
> +
> + # Run until a crash and confirm GDB displays memory tag violation
> + # information for async mode
> + gdb_test "continue" \
> + [multi_line \
> + "Program received signal SIGSEGV, Segmentation fault" \
> + "Memory tag violation" \
> + "Fault address unavailable\." \
> + "$hex in .* \\(.*\\) .*"] \
> + "display tag violation information"
> +}
> diff --git a/gdb/testsuite/gdb.base/memtag.c b/gdb/testsuite/gdb.base/memtag.c
> new file mode 100644
> index 0000000000..63a42ae278
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/memtag.c
> @@ -0,0 +1,22 @@
> +/* This test program is part of GDB, the GNU debugger.
> +
> + Copyright 2020 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/>. */
> +
> +int
> +main (int argc, char **argv)
> +{
> + return 0;
> +}
> diff --git a/gdb/testsuite/gdb.base/memtag.exp b/gdb/testsuite/gdb.base/memtag.exp
> new file mode 100644
> index 0000000000..484a78e828
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/memtag.exp
> @@ -0,0 +1,64 @@
> +# Copyright 2020 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/>.
> +
> +# Smoke testing for the various memory tagging commands in GDB.
> +
> +set u_msg "Memory tagging not supported or disabled by the current architecture\."
> +
> +standard_testfile
> +if {[prepare_for_testing "failed to prepare" ${testfile} ${srcfile}]} {
> + return -1
> +}
> +
> +if {[target_info gdb_protocol] == "extended-remote"} {
> + # Make sure we're disconnected, in case we're testing with an
> + # extended-remote board, therefore already connected.
> + gdb_test "disconnect" ".*"
> +}
> +
> +# Test commands without running the program.
> +with_test_prefix "before program execution" {
> + # These commands should all fails without a running program.
> + foreach subcmd {"withltag" "showltag" "setatag" "showatag" "check"} {
> + gdb_test "mtag $subcmd" $u_msg
> + }
> +}
> +
> +clean_restart $testfile
> +
> +if ![runto_main] {
> + untested "could not run to main"
> + return -1
> +}
> +
> +# Targets that don't support memory tagging should not execute the
> +# runtime memory tagging tests.
> +if {![supports_memtag]} {
> + untested "memory tagging unsupported"
> + return -1
> +}
> +
> +# With the program running, try to use the memory tagging commands.
> +with_test_prefix "during program execution" {
> + set msg "Argument required \\(address or pointer\\)\."
> +
> + # Test the various mtag commands again.
> + gdb_test "mtag showltag" $msg
> + gdb_test "mtag showatag" $msg
> + gdb_test "mtag withltag" "Argument required \\( <tag>\\)\."
> + gdb_test "mtag setatag" \
> + "Argument required \\(<starting address> <length> <tag bytes>\\)\."
> + gdb_test "mtag check" $msg
> +}
> diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> index 55154db6a5..347704ce0a 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -2679,6 +2679,22 @@ proc supports_get_siginfo_type {} {
> }
> }
>
> +# Return 1 if memory tagging is supported at runtime, otherwise return 0.
> +
> +proc supports_memtag {} {
> + global gdb_prompt
> +
> + gdb_test_multiple "mtag check" "" {
> + -re "Memory tagging not supported or disabled by the current architecture\..*$gdb_prompt $" {
> + return 0
> + }
> + -re "Argument required \\(address or pointer\\).*$gdb_prompt $" {
> + return 1
> + }
> + }
> + return 0
> +}
> +
> # Return 1 if the target supports hardware single stepping.
>
> proc can_hardware_single_step {} {
> --
> 2.17.1
>