"""
Test "memory tag read" and "memory tag write" commands
on AArch64 Linux with MTE.
"""
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
class AArch64LinuxMTEMemoryTagAccessTestCase(TestBase):
NO_DEBUG_INFO_TESTCASE = True
def setup_mte_test(self):
if not self.isAArch64MTE():
self.skipTest("Target must support MTE.")
# Required to check that commands remove non-address bits
# other than the memory tags.
if not self.isAArch64PAuth():
self.skipTest("Target must support pointer authentication")
self.build()
self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
lldbutil.run_break_set_by_file_and_line(
self,
"main.c",
line_number("main.c", "// Breakpoint here"),
num_expected_locations=1,
)
self.runCmd("run", RUN_SUCCEEDED)
if self.process().GetState() == lldb.eStateExited:
self.fail("Test program failed to run.")
self.expect(
"thread list",
STOPPED_DUE_TO_BREAKPOINT,
substrs=["stopped", "stop reason = breakpoint"],
)
@skipUnlessArch("aarch64")
@skipUnlessPlatform(["linux"])
@skipUnlessAArch64MTELinuxCompiler
def test_mte_tag_read(self):
self.setup_mte_test()
# Argument validation
self.expect(
"memory tag read",
substrs=[
"error: wrong number of arguments; expected at least <address-expression>, "
"at most <address-expression> <end-address-expression>"
],
error=True,
)
self.expect(
"memory tag read mte_buf buf+16 32",
substrs=[
"error: wrong number of arguments; expected at least <address-expression>, "
"at most <address-expression> <end-address-expression>"
],
error=True,
)
self.expect(
"memory tag read not_a_symbol",
substrs=[
'error: Invalid address expression, address expression "not_a_symbol" '
"evaluation failed"
],
error=True,
)
self.expect(
"memory tag read mte_buf not_a_symbol",
substrs=[
'error: Invalid end address expression, address expression "not_a_symbol" '
"evaluation failed"
],
error=True,
)
# Inverted range
self.expect(
"memory tag read mte_buf mte_buf-16",
patterns=[
"error: End address \(0x[A-Fa-f0-9]+\) must be "
"greater than the start address \(0x[A-Fa-f0-9]+\)"
],
error=True,
)
# Range of length 0
self.expect(
"memory tag read mte_buf mte_buf",
patterns=[
"error: End address \(0x[A-Fa-f0-9]+\) must be "
"greater than the start address \(0x[A-Fa-f0-9]+\)"
],
error=True,
)
# Can't read from a region without tagging
self.expect(
"memory tag read non_mte_buf",
patterns=[
"error: Address range 0x[0-9A-Fa-f]+00:0x[0-9A-Fa-f]+10 is not "
"in a memory tagged region"
],
error=True,
)
# If there's no end address we assume 1 granule
self.expect(
"memory tag read mte_buf",
patterns=[
"Logical tag: 0x9\n"
"Allocation tags:\n"
"\[0x[0-9A-Fa-f]+00, 0x[0-9A-Fa-f]+10\): 0x0 \(mismatch\)$"
],
)
# Range of <1 granule is rounded up to 1 granule
self.expect(
"memory tag read mte_buf mte_buf+8",
patterns=[
"Logical tag: 0x9\n"
"Allocation tags:\n"
"\[0x[0-9A-Fa-f]+00, 0x[0-9A-Fa-f]+10\): 0x0 \(mismatch\)$"
],
)
# Start address is aligned down, end aligned up
self.expect(
"memory tag read mte_buf+8 mte_buf+24",
patterns=[
"Logical tag: 0x9\n"
"Allocation tags:\n"
"\[0x[0-9A-Fa-f]+00, 0x[0-9A-Fa-f]+10\): 0x0 \(mismatch\)\n"
"\[0x[0-9A-Fa-f]+10, 0x[0-9A-Fa-f]+20\): 0x1 \(mismatch\)$"
],
)
# You may read up to the end of the tagged region
# Layout is mte_buf, mte_buf_2, non_mte_buf.
# So we read from the end of mte_buf_2 here.
self.expect(
"memory tag read mte_buf_2+page_size-16 mte_buf_2+page_size",
patterns=[
"Logical tag: 0x0\n"
"Allocation tags:\n"
"\[0x[0-9A-Fa-f]+, 0x[0-9A-Fa-f]+\): 0x0$"
],
)
# Ranges with any part outside the region will error
self.expect(
"memory tag read mte_buf_2+page_size-16 mte_buf_2+page_size+32",
patterns=[
"error: Address range 0x[0-9A-Fa-f]+f0:0x[0-9A-Fa-f]+20 "
"is not in a memory tagged region"
],
error=True,
)
self.expect(
"memory tag read mte_buf_2+page_size",
patterns=[
"error: Address range 0x[0-9A-Fa-f]+00:0x[0-9A-Fa-f]+10 "
"is not in a memory tagged region"
],
error=True,
)
# You can read a range that spans more than one mapping
# This spills into mte_buf2 which is also MTE
self.expect(
"memory tag read mte_buf+page_size-16 mte_buf+page_size+16",
patterns=[
"Logical tag: 0x9\n"
"Allocation tags:\n"
"\[0x[0-9A-Fa-f]+f0, 0x[0-9A-Fa-f]+00\): 0xf \(mismatch\)\n"
"\[0x[0-9A-Fa-f]+00, 0x[0-9A-Fa-f]+10\): 0x0 \(mismatch\)$"
],
)
# Top byte is ignored when creating the range, not just the 4 tag bits.
# So even though these two pointers have different top bytes
# and the start's is > the end's, this is not an error.
self.expect(
"memory tag read mte_buf_alt_tag mte_buf+16",
patterns=[
"Logical tag: 0xa\n"
"Allocation tags:\n"
"\[0x[0-9A-Fa-f]+00, 0x[0-9A-Fa-f]+10\): 0x0 \(mismatch\)$"
],
)
# Mismatched tags are marked. The logical tag is taken from the start address.
self.expect(
"memory tag read mte_buf+(8*16) mte_buf_alt_tag+(8*16)+48",
patterns=[
"Logical tag: 0x9\n"
"Allocation tags:\n"
"\[0x[0-9A-Fa-f]+80, 0x[0-9A-Fa-f]+90\): 0x8 \(mismatch\)\n"
"\[0x[0-9A-Fa-f]+90, 0x[0-9A-Fa-f]+a0\): 0x9\n"
"\[0x[0-9A-Fa-f]+a0, 0x[0-9A-Fa-f]+b0\): 0xa \(mismatch\)$"
],
)
@skipUnlessArch("aarch64")
@skipUnlessPlatform(["linux"])
@skipUnlessAArch64MTELinuxCompiler
def test_mte_tag_write(self):
self.setup_mte_test()
# Argument validation
self.expect(
"memory tag write",
substrs=[
" wrong number of arguments; expected "
"<address-expression> <tag> [<tag> [...]]"
],
error=True,
)
self.expect(
"memory tag write mte_buf",
substrs=[
" wrong number of arguments; expected "
"<address-expression> <tag> [<tag> [...]]"
],
error=True,
)
self.expect(
"memory tag write not_a_symbol 9",
substrs=[
'error: Invalid address expression, address expression "not_a_symbol" '
"evaluation failed"
],
error=True,
)
# Can't write to a region without tagging
self.expect(
"memory tag write non_mte_buf 9",
patterns=[
"error: Address range 0x[0-9A-Fa-f]+00:0x[0-9A-Fa-f]+10 is not "
"in a memory tagged region"
],
error=True,
)
# Start address is aligned down so we write to the granule that contains it
self.expect("memory tag write mte_buf+8 9")
# Make sure we only modified the first granule
self.expect(
"memory tag read mte_buf mte_buf+32",
patterns=[
"Logical tag: 0x9\n"
"Allocation tags:\n"
"\[0x[0-9A-Fa-f]+00, 0x[0-9A-Fa-f]+10\): 0x9\n"
"\[0x[0-9A-Fa-f]+10, 0x[0-9A-Fa-f]+20\): 0x1 \(mismatch\)$"
],
)
# You can write multiple tags, range calculated for you
self.expect("memory tag write mte_buf 10 11 12")
self.expect(
"memory tag read mte_buf mte_buf+48",
patterns=[
"Logical tag: 0x9\n"
"Allocation tags:\n"
"\[0x[0-9A-Fa-f]+00, 0x[0-9A-Fa-f]+10\): 0xa \(mismatch\)\n"
"\[0x[0-9A-Fa-f]+10, 0x[0-9A-Fa-f]+20\): 0xb \(mismatch\)\n"
"\[0x[0-9A-Fa-f]+20, 0x[0-9A-Fa-f]+30\): 0xc \(mismatch\)$"
],
)
# You may write up to the end of a tagged region
# (mte_buf_2's intial tags will all be 0)
self.expect("memory tag write mte_buf_2+page_size-16 0xe")
self.expect(
"memory tag read mte_buf_2+page_size-16 mte_buf_2+page_size",
patterns=[
"Logical tag: 0x0\n"
"Allocation tags:\n"
"\[0x[0-9A-Fa-f]+, 0x[0-9A-Fa-f]+\): 0xe \(mismatch\)$"
],
)
# Ranges with any part outside the region will error
self.expect(
"memory tag write mte_buf_2+page_size-16 6 7",
patterns=[
"error: Address range 0x[0-9A-Fa-f]+f0:0x[0-9A-Fa-f]+10 "
"is not in a memory tagged region"
],
error=True,
)
self.expect(
"memory tag write mte_buf_2+page_size 6",
patterns=[
"error: Address range 0x[0-9A-Fa-f]+00:0x[0-9A-Fa-f]+10 "
"is not in a memory tagged region"
],
error=True,
)
self.expect(
"memory tag write mte_buf_2+page_size 6 7 8",
patterns=[
"error: Address range 0x[0-9A-Fa-f]+00:0x[0-9A-Fa-f]+30 "
"is not in a memory tagged region"
],
error=True,
)
# You can write to a range that spans two mappings, as long
# as they are both tagged.
# buf and buf2 are next to each other so this wirtes into buf2.
self.expect("memory tag write mte_buf+page_size-16 1 2")
self.expect(
"memory tag read mte_buf+page_size-16 mte_buf+page_size+16",
patterns=[
"Logical tag: 0x9\n"
"Allocation tags:\n"
"\[0x[0-9A-Fa-f]+f0, 0x[0-9A-Fa-f]+00\): 0x1 \(mismatch\)\n"
"\[0x[0-9A-Fa-f]+00, 0x[0-9A-Fa-f]+10\): 0x2 \(mismatch\)$"
],
)
# Even if a page is read only the debugger can still write to it
self.expect("memory tag write mte_read_only 1")
self.expect(
"memory tag read mte_read_only",
patterns=[
"Logical tag: 0x0\n"
"Allocation tags:\n"
"\[0x[0-9A-Fa-f]+00, 0x[0-9A-Fa-f]+10\): 0x1 \(mismatch\)$"
],
)
# Trying to write a value > maximum tag value is an error
self.expect(
"memory tag write mte_buf 99",
patterns=["error: Found tag 0x63 which is > max MTE tag value of 0xf."],
error=True,
)
# You can provide an end address and have lldb repeat the tags as needed
# The range is checked in the same way it is for "memory tag read"
self.expect(
"memory tag write mte_buf 9 -e",
patterns=["error: last option requires an argument"],
error=True,
)
self.expect(
"memory tag write mte_buf 9 -e food",
patterns=['error: address expression "food" evaluation failed'],
error=True,
)
self.expect(
"memory tag write mte_buf_2 9 --end-addr mte_buf_2",
patterns=[
"error: End address \(0x[A-Fa-f0-9]+\) must be "
"greater than the start address \(0x[A-Fa-f0-9]+\)"
],
error=True,
)
self.expect(
"memory tag write mte_buf_2 9 --end-addr mte_buf_2-16",
patterns=[
"error: End address \(0x[A-Fa-f0-9]+\) must be "
"greater than the start address \(0x[A-Fa-f0-9]+\)"
],
error=True,
)
self.expect(
"memory tag write mte_buf_2 9 --end-addr mte_buf_2+page_size+16",
patterns=[
"error: Address range 0x[0-9A-Fa-f]+00:0x[0-9A-Fa-f]+10 "
"is not in a memory tagged region"
],
error=True,
)
# Tags are repeated across the range
# For these we'll read one extra to make sure we don't over write
self.expect("memory tag write mte_buf_2 4 5 --end-addr mte_buf_2+48")
self.expect(
"memory tag read mte_buf_2 mte_buf_2+64",
patterns=[
"Logical tag: 0x0\n"
"Allocation tags:\n"
"\[0x[0-9A-Fa-f]+00, 0x[0-9A-Fa-f]+10\): 0x4 \(mismatch\)\n"
"\[0x[0-9A-Fa-f]+10, 0x[0-9A-Fa-f]+20\): 0x5 \(mismatch\)\n"
"\[0x[0-9A-Fa-f]+20, 0x[0-9A-Fa-f]+30\): 0x4 \(mismatch\)\n"
"\[0x[0-9A-Fa-f]+30, 0x[0-9A-Fa-f]+40\): 0x0$"
],
)
# Since this aligns like tag read does, the start is aligned down and the end up.
# Meaning that start/end tells you the start/end granule that will be written.
# This matters particularly if either are misaligned.
# Here start moves down so the final range is mte_buf_2 -> mte_buf_2+32
self.expect("memory tag write mte_buf_2+8 6 -end-addr mte_buf_2+32")
self.expect(
"memory tag read mte_buf_2 mte_buf_2+48",
patterns=[
"Logical tag: 0x0\n"
"Allocation tags:\n"
"\[0x[0-9A-Fa-f]+00, 0x[0-9A-Fa-f]+10\): 0x6 \(mismatch\)\n"
"\[0x[0-9A-Fa-f]+10, 0x[0-9A-Fa-f]+20\): 0x6 \(mismatch\)\n"
"\[0x[0-9A-Fa-f]+20, 0x[0-9A-Fa-f]+30\): 0x4 \(mismatch\)$"
],
)
# If we do the same with a misaligned end, it also moves but upward.
# The intial range is 2 granules but the final range is mte_buf_2 -> mte_buf_2+48
self.expect("memory tag write mte_buf_2+8 3 -end-addr mte_buf_2+32+8")
self.expect(
"memory tag read mte_buf_2 mte_buf_2+64",
patterns=[
"Logical tag: 0x0\n"
"Allocation tags:\n"
"\[0x[0-9A-Fa-f]+00, 0x[0-9A-Fa-f]+10\): 0x3 \(mismatch\)\n"
"\[0x[0-9A-Fa-f]+10, 0x[0-9A-Fa-f]+20\): 0x3 \(mismatch\)\n"
"\[0x[0-9A-Fa-f]+20, 0x[0-9A-Fa-f]+30\): 0x3 \(mismatch\)\n"
"\[0x[0-9A-Fa-f]+30, 0x[0-9A-Fa-f]+40\): 0x0$"
],
)
@skipUnlessArch("aarch64")
@skipUnlessPlatform(["linux"])
@skipUnlessAArch64MTELinuxCompiler
def test_mte_memory_read_tag_display(self):
self.setup_mte_test()
# Reading from an untagged range should not be any different
self.expect(
"memory read non_mte_buf non_mte_buf+16", substrs=["tag"], matching=False
)
# show-tags option is required
self.expect(
'memory read mte_buf mte_buf+32 -f "x" -l 1 -s 16',
patterns=["tag"],
matching=False,
)
# Reading 16 bytes per line means 1 granule and so 1 tag per line
self.expect(
'memory read mte_buf mte_buf+32 -f "x" -l 1 -s 16 --show-tags',
patterns=[
"0x[0-9A-Fa-f]+00: 0x0+ \(tag: 0x0\)\n"
"0x[0-9A-Fa-f]+10: 0x0+ \(tag: 0x1\)"
],
)
# If bytes per line is > granule size then you get multiple tags
# per line.
self.expect(
'memory read mte_buf mte_buf+32 -f "x" -l 1 -s 32 --show-tags',
patterns=["0x[0-9A-Fa-f]+00: 0x0+ \(tags: 0x0 0x1\)\n"],
)
# Reading half a granule still shows you the tag for that granule
self.expect(
'memory read mte_buf mte_buf+8 -f "x" -l 1 -s 8 --show-tags',
patterns=["0x[0-9A-Fa-f]+00: 0x0+ \(tag: 0x0\)\n"],
)
# We can read a whole number of granules but split them over more lines
# than there are granules. Tags are shown repeated for each applicable line.
self.expect(
'memory read mte_buf+32 mte_buf+64 -f "x" -l 1 -s 8 --show-tags',
patterns=[
"0x[0-9A-Fa-f]+20: 0x0+ \(tag: 0x2\)\n"
"0x[0-9A-Fa-f]+28: 0x0+ \(tag: 0x2\)\n"
"0x[0-9A-Fa-f]+30: 0x0+ \(tag: 0x3\)\n"
"0x[0-9A-Fa-f]+38: 0x0+ \(tag: 0x3\)"
],
)
# Also works if we misalign the start address. Note the first tag is shown
# only once here and we have a new tag on the last line.
# (bytes per line == the misalignment here)
self.expect(
'memory read mte_buf+32+8 mte_buf+64+8 -f "x" -l 1 -s 8 --show-tags',
patterns=[
"0x[0-9A-Fa-f]+28: 0x0+ \(tag: 0x2\)\n"
"0x[0-9A-Fa-f]+30: 0x0+ \(tag: 0x3\)\n"
"0x[0-9A-Fa-f]+38: 0x0+ \(tag: 0x3\)\n"
"0x[0-9A-Fa-f]+40: 0x0+ \(tag: 0x4\)"
],
)
# We can do the same thing but where the misaligment isn't equal to
# bytes per line. This time, some lines cover multiple granules and
# so show multiple tags.
self.expect(
'memory read mte_buf+32+4 mte_buf+64+4 -f "x" -l 1 -s 8 --show-tags',
patterns=[
"0x[0-9A-Fa-f]+24: 0x0+ \(tag: 0x2\)\n"
"0x[0-9A-Fa-f]+2c: 0x0+ \(tags: 0x2 0x3\)\n"
"0x[0-9A-Fa-f]+34: 0x0+ \(tag: 0x3\)\n"
"0x[0-9A-Fa-f]+3c: 0x0+ \(tags: 0x3 0x4\)"
],
)
# If you read a range that includes non tagged areas those areas
# simply aren't annotated.
# Initial part of range is untagged
self.expect(
'memory read mte_buf-16 mte_buf+32 -f "x" -l 1 -s 16 --show-tags',
patterns=[
"0x[0-9A-Fa-f]+f0: 0x0+\n"
"0x[0-9A-Fa-f]+00: 0x0+ \(tag: 0x0\)\n"
"0x[0-9A-Fa-f]+10: 0x0+ \(tag: 0x1\)"
],
)
# End of range is untagged
self.expect(
'memory read mte_buf+page_size-16 mte_buf+page_size+16 -f "x" -l 1 -s 16 --show-tags',
patterns=["0x[0-9A-Fa-f]+f0: 0x0+ \(tag: 0xf\)\n" "0x[0-9A-Fa-f]+00: 0x0+"],
)
# The smallest MTE range we can get is a single page so we just check
# parts of this result. Where we read from before the tagged page to after it.
# Add --force here because we're reading just over 4k.
self.expect(
'memory read mte_read_only-16 mte_read_only+page_size+16 -f "x" -l 1 -s 16 --force --show-tags',
patterns=[
"0x[0-9A-Fa-f]+f0: 0x0+\n" "0x[0-9A-Fa-f]+00: 0x0+ \(tag: 0x0\)\n",
"0x[0-9A-Fa-f]+f0: 0x0+ \(tag: 0x0\)\n" "0x[0-9A-Fa-f]+00: 0x0+",
],
)
# Some parts of a line might be tagged and others untagged.
# <no tag> is shown in where the tag would be, to keep the order intact.
self.expect(
'memory read mte_buf-16 mte_buf+32 -f "x" -l 1 -s 32 --show-tags',
patterns=["0x[0-9A-Fa-f]+f0: 0x0+ \(tags: <no tag> 0x0\)"],
)
self.expect(
'memory read mte_read_only+page_size-16 mte_read_only+page_size+16 -f "x" -l 1 -s 32 --show-tags',
patterns=["0x[0-9A-Fa-f]+f0: 0x0+ \(tags: 0x0 <no tag>\)"],
)
# Here the start address is unaligned so we cover 3 granules instead of 2
self.expect(
'memory read mte_buf-16+4 mte_buf+32+4 -f "x" -l 1 -s 32 --show-tags',
patterns=["0x[0-9A-Fa-f]+f4: 0x0+ \(tags: <no tag> 0x0 0x1\)"],
)
self.expect(
'memory read mte_read_only+page_size-16+4 mte_read_only+page_size+16+4 -f "x" -l 1 -s 32 --show-tags',
patterns=["0x[0-9A-Fa-f]+f4: 0x0+ \(tags: 0x0 <no tag> <no tag>\)"],
)
# Some formats call DumpDataExtractor multiple times,
# check that those print tags only once per line.
self.expect(
'memory read mte_buf mte_buf+32 -f "x" --show-tags',
patterns=[
"0x[0-9A-Fa-f]+00: 0x0+ 0x0+ 0x0+ 0x0+ \(tag: 0x0\)\n",
"0x[0-9A-Fa-f]+10: 0x0+ 0x0+ 0x0+ 0x0+ \(tag: 0x1\)",
],
)
self.expect(
'memory read mte_buf mte_buf+32 -f "bytes with ASCII" --show-tags',
patterns=[
"0x[0-9A-Fa-f]+00: (00 ){16} \.{16} \(tag: 0x0\)\n",
"0x[0-9A-Fa-f]+10: (00 ){16} \.{16} \(tag: 0x1\)",
],
)
self.expect(
'memory read mte_buf mte_buf+32 -f "uint8_t[]" -s 16 -l 1 --show-tags',
patterns=[
"0x[0-9A-Fa-f]+00: \{(0x00 ){15}0x00\} \(tag: 0x0\)\n"
"0x[0-9A-Fa-f]+10: \{(0x00 ){15}0x00\} \(tag: 0x1\)"
],
)
@skipUnlessArch("aarch64")
@skipUnlessPlatform(["linux"])
@skipUnlessAArch64MTELinuxCompiler
def test_mte_memory_read_tag_display_repeated(self):
"""Test that the --show-tags option is kept when repeating the memory read command."""
self.setup_mte_test()
self.expect(
'memory read mte_buf mte_buf+16 -f "x" --show-tags',
patterns=["0x[0-9A-fa-f]+00: 0x0+ 0x0+ 0x0+ 0x0+ \(tag: 0x0\)"],
)
# Equivalent to just pressing enter on the command line.
self.expect(
"memory read",
patterns=["0x[0-9A-fa-f]+10: 0x0+ 0x0+ 0x0+ 0x0+ \(tag: 0x1\)"],
)
# You can add the argument to an existing repetition without resetting
# the whole command. Though all other optional arguments will reset to
# their default values when you do this.
self.expect(
'memory read mte_buf mte_buf+16 -f "x"',
patterns=["0x[0-9A-fa-f]+00: 0x0+ 0x0+ 0x0+ 0x0+"],
)
self.expect("memory read", patterns=["0x[0-9A-fa-f]+10: 0x0+ 0x0+ 0x0+ 0x0+"])
# Note that the formatting returns to default here.
self.expect(
"memory read --show-tags",
patterns=["0x[0-9A-fa-f]+20: (00 )+ \.+ \(tag: 0x2\)"],
)
self.expect(
"memory read", patterns=["0x[0-9A-fa-f]+30: (00 )+ \.+ \(tag: 0x3\)"]
)
# A fresh command reverts to the default of tags being off.
self.expect(
'memory read mte_buf mte_buf+16 -f "x"',
patterns=["0x[0-9A-fa-f]+00: 0x0+ 0x0+ 0x0+ 0x0+"],
)
@skipUnlessArch("aarch64")
@skipUnlessPlatform(["linux"])
@skipUnlessAArch64MTELinuxCompiler
def test_mte_memory_find(self):
"""Test the --show-tags option with memory find."""
self.setup_mte_test()
# No result, nothing changes.
self.expect(
'memory find -s "foo" mte_buf mte_buf+32 --show-tags',
substrs=["data not found within the range."],
)
cmd = 'memory find -s "LLDB" mte_buf+64 mte_buf+512'
found_pattern = "data found at location: 0x[0-9A-Fa-f]+80"
results_patterns = [
"0x[0-9A-Fa-f]+80: 4c 4c 44 42 (00 )+ LLDB\.+",
"0x[0-9A-Fa-f]+90: 00 00 00 00 (00 )+ \.+",
]
# Default is not to show tags
self.expect(cmd, patterns=[found_pattern, *results_patterns])
self.expect(
cmd + " --show-tags",
patterns=[
found_pattern,
results_patterns[0] + " \(tag: 0x8\)",
results_patterns[1] + " \(tag: 0x9\)",
],
)
# Uses the same logic as memory read to handle misalignment.
self.expect(
'memory find -s "DB" mte_buf+64 mte_buf+512 --show-tags',
patterns=[
"data found at location: 0x[0-9A-Fa-f]+82\n"
"0x[0-9A-Fa-f]+82: 44 42 (00 )+ DB\.+ \(tags: 0x8 0x9\)\n",
"0x[0-9A-Fa-f]+92: 00 00 (00 )+ ..\.+ \(tags: 0x9 0xa\)",
],
)