[Lldb-commits] [lldb] 2f9fa9e - [lldb][AArch64] Add support for memory tags in core files
David Spickett via lldb-commits
lldb-commits at lists.llvm.org
Tue Jul 26 00:46:42 PDT 2022
Author: David Spickett
Date: 2022-07-26T08:46:36+01:00
New Revision: 2f9fa9ef5387de3d87b0c866c678d93695c1c1f3
URL: https://github.com/llvm/llvm-project/commit/2f9fa9ef5387de3d87b0c866c678d93695c1c1f3
DIFF: https://github.com/llvm/llvm-project/commit/2f9fa9ef5387de3d87b0c866c678d93695c1c1f3.diff
LOG: [lldb][AArch64] Add support for memory tags in core files
This teaches ProcessElfCore to recognise the MTE tag segments.
https://www.kernel.org/doc/html/latest/arm64/memory-tagging-extension.html#core-dump-support
These segments contain all the tags for a matching memory segment
which will have the same size in virtual address terms. In real terms
it's 2 tags per byte so the data in the segment is much smaller.
Since MTE is the only tag type supported I have hardcoded some
things to those values. We could and should support more formats
as they appear but doing so now would leave code untested until that
happens.
A few things to note:
* /proc/pid/smaps is not in the core file, only the details you have
in "maps". Meaning we mark a region tagged only if it has a tag segment.
* A core file supports memory tagging if it has at least 1 memory
tag segment, there is no other flag we can check to tell if memory
tagging was enabled. (unlike a live process that can support memory
tagging even if there are currently no tagged memory regions)
Tests have been added at the commands level for a core file with
mte and without.
There is a lot of overlap between the "memory tag read" tests here and the unit tests for
MemoryTagManagerAArch64MTE::UnpackTagsFromCoreFileSegment, but I think it's
worth keeping to check ProcessElfCore doesn't cause an assert.
Depends on D129487
Reviewed By: omjavaid
Differential Revision: https://reviews.llvm.org/D129489
Added:
lldb/test/API/linux/aarch64/mte_core_file/TestAArch64LinuxMTEMemoryTagCoreFile.py
lldb/test/API/linux/aarch64/mte_core_file/core.mte
lldb/test/API/linux/aarch64/mte_core_file/core.nomte
lldb/test/API/linux/aarch64/mte_core_file/main.c
Modified:
lldb/include/lldb/Target/Process.h
lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
llvm/docs/ReleaseNotes.rst
llvm/include/llvm/BinaryFormat/ELF.h
Removed:
################################################################################
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index a55659225ef19..505e211e09b63 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -1715,8 +1715,8 @@ class Process : public std::enable_shared_from_this<Process>,
/// an error saying so.
/// If it does, either the memory tags or an error describing a
/// failure to read or unpack them.
- llvm::Expected<std::vector<lldb::addr_t>> ReadMemoryTags(lldb::addr_t addr,
- size_t len);
+ virtual llvm::Expected<std::vector<lldb::addr_t>>
+ ReadMemoryTags(lldb::addr_t addr, size_t len);
/// Write memory tags for a range of memory.
/// (calls DoWriteMemoryTags to do the target specific work)
diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
index 24c942f1d290a..24d3c4bd0ba24 100644
--- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
+++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
@@ -144,6 +144,18 @@ lldb::addr_t ProcessElfCore::AddAddressRangeFromLoadSegment(
return addr;
}
+lldb::addr_t ProcessElfCore::AddAddressRangeFromMemoryTagSegment(
+ const elf::ELFProgramHeader &header) {
+ // If lldb understood multiple kinds of tag segments we would record the type
+ // of the segment here also. As long as there is only 1 type lldb looks for,
+ // there is no need.
+ FileRange file_range(header.p_offset, header.p_filesz);
+ m_core_tag_ranges.Append(
+ VMRangeToFileOffset::Entry(header.p_vaddr, header.p_memsz, file_range));
+
+ return header.p_vaddr;
+}
+
// Process Control
Status ProcessElfCore::DoLoadCore() {
Status error;
@@ -170,9 +182,12 @@ Status ProcessElfCore::DoLoadCore() {
bool ranges_are_sorted = true;
lldb::addr_t vm_addr = 0;
+ lldb::addr_t tag_addr = 0;
/// Walk through segments and Thread and Address Map information.
/// PT_NOTE - Contains Thread and Register information
/// PT_LOAD - Contains a contiguous range of Process Address Space
+ /// PT_AARCH64_MEMTAG_MTE - Contains AArch64 MTE memory tags for a range of
+ /// Process Address Space.
for (const elf::ELFProgramHeader &H : segments) {
DataExtractor data = core->GetSegmentData(H);
@@ -187,12 +202,18 @@ Status ProcessElfCore::DoLoadCore() {
if (vm_addr > last_addr)
ranges_are_sorted = false;
vm_addr = last_addr;
+ } else if (H.p_type == llvm::ELF::PT_AARCH64_MEMTAG_MTE) {
+ lldb::addr_t last_addr = AddAddressRangeFromMemoryTagSegment(H);
+ if (tag_addr > last_addr)
+ ranges_are_sorted = false;
+ tag_addr = last_addr;
}
}
if (!ranges_are_sorted) {
m_core_aranges.Sort();
m_core_range_infos.Sort();
+ m_core_tag_ranges.Sort();
}
// Even if the architecture is set in the target, we need to override it to
@@ -310,6 +331,15 @@ Status ProcessElfCore::DoGetMemoryRegionInfo(lldb::addr_t load_addr,
? MemoryRegionInfo::eYes
: MemoryRegionInfo::eNo);
region_info.SetMapped(MemoryRegionInfo::eYes);
+
+ // A region is memory tagged if there is a memory tag segment that covers
+ // the exact same range.
+ region_info.SetMemoryTagged(MemoryRegionInfo::eNo);
+ const VMRangeToFileOffset::Entry *tag_entry =
+ m_core_tag_ranges.FindEntryStartsAt(permission_entry->GetRangeBase());
+ if (tag_entry &&
+ tag_entry->GetRangeEnd() == permission_entry->GetRangeEnd())
+ region_info.SetMemoryTagged(MemoryRegionInfo::eYes);
} else if (load_addr < permission_entry->GetRangeBase()) {
region_info.GetRange().SetRangeBase(load_addr);
region_info.GetRange().SetRangeEnd(permission_entry->GetRangeBase());
@@ -317,6 +347,7 @@ Status ProcessElfCore::DoGetMemoryRegionInfo(lldb::addr_t load_addr,
region_info.SetWritable(MemoryRegionInfo::eNo);
region_info.SetExecutable(MemoryRegionInfo::eNo);
region_info.SetMapped(MemoryRegionInfo::eNo);
+ region_info.SetMemoryTagged(MemoryRegionInfo::eNo);
}
return Status();
}
@@ -327,6 +358,7 @@ Status ProcessElfCore::DoGetMemoryRegionInfo(lldb::addr_t load_addr,
region_info.SetWritable(MemoryRegionInfo::eNo);
region_info.SetExecutable(MemoryRegionInfo::eNo);
region_info.SetMapped(MemoryRegionInfo::eNo);
+ region_info.SetMemoryTagged(MemoryRegionInfo::eNo);
return Status();
}
@@ -376,6 +408,38 @@ size_t ProcessElfCore::DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
return bytes_copied;
}
+llvm::Expected<std::vector<lldb::addr_t>>
+ProcessElfCore::ReadMemoryTags(lldb::addr_t addr, size_t len) {
+ ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
+ if (core_objfile == nullptr)
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "No core object file.");
+
+ llvm::Expected<const MemoryTagManager *> tag_manager_or_err =
+ GetMemoryTagManager();
+ if (!tag_manager_or_err)
+ return tag_manager_or_err.takeError();
+
+ // LLDB only supports AArch64 MTE tag segments so we do not need to worry
+ // about the segment type here. If you got here then you must have a tag
+ // manager (meaning you are debugging AArch64) and all the segments in this
+ // list will have had type PT_AARCH64_MEMTAG_MTE.
+ const VMRangeToFileOffset::Entry *tag_entry =
+ m_core_tag_ranges.FindEntryThatContains(addr);
+ // If we don't have a tag segment or the range asked for extends outside the
+ // segment.
+ if (!tag_entry || (addr + len) >= tag_entry->GetRangeEnd())
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "No tag segment that covers this range.");
+
+ const MemoryTagManager *tag_manager = *tag_manager_or_err;
+ return tag_manager->UnpackTagsFromCoreFileSegment(
+ [core_objfile](lldb::offset_t offset, size_t length, void *dst) {
+ return core_objfile->CopyData(offset, length, dst);
+ },
+ tag_entry->GetRangeBase(), tag_entry->data.GetRangeBase(), addr, len);
+}
+
void ProcessElfCore::Clear() {
m_thread_list.Clear();
diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
index fd36e50278168..03c23378e3c16 100644
--- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
+++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
@@ -86,6 +86,11 @@ class ProcessElfCore : public lldb_private::PostMortemProcess {
size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
lldb_private::Status &error) override;
+ // We do not implement DoReadMemoryTags. Instead all the work is done in
+ // ReadMemoryTags which avoids having to unpack and repack tags.
+ llvm::Expected<std::vector<lldb::addr_t>> ReadMemoryTags(lldb::addr_t addr,
+ size_t len) override;
+
lldb::addr_t GetImageInfoAddress() override;
lldb_private::ArchSpec GetArchitecture();
@@ -105,6 +110,8 @@ class ProcessElfCore : public lldb_private::PostMortemProcess {
DoGetMemoryRegionInfo(lldb::addr_t load_addr,
lldb_private::MemoryRegionInfo ®ion_info) override;
+ bool SupportsMemoryTagging() override { return !m_core_tag_ranges.IsEmpty(); }
+
private:
struct NT_FILE_Entry {
lldb::addr_t start;
@@ -139,6 +146,9 @@ class ProcessElfCore : public lldb_private::PostMortemProcess {
// Permissions for all ranges
VMRangeToPermissions m_core_range_infos;
+ // Memory tag ranges found in the core
+ VMRangeToFileOffset m_core_tag_ranges;
+
// NT_FILE entries found from the NOTE segment
std::vector<NT_FILE_Entry> m_nt_file_entries;
@@ -154,6 +164,10 @@ class ProcessElfCore : public lldb_private::PostMortemProcess {
lldb::addr_t
AddAddressRangeFromLoadSegment(const elf::ELFProgramHeader &header);
+ // Parse a contiguous address range from a memory tag segment
+ lldb::addr_t
+ AddAddressRangeFromMemoryTagSegment(const elf::ELFProgramHeader &header);
+
llvm::Expected<std::vector<lldb_private::CoreNote>>
parseSegment(const lldb_private::DataExtractor &segment);
llvm::Error parseFreeBSDNotes(llvm::ArrayRef<lldb_private::CoreNote> notes);
diff --git a/lldb/test/API/linux/aarch64/mte_core_file/TestAArch64LinuxMTEMemoryTagCoreFile.py b/lldb/test/API/linux/aarch64/mte_core_file/TestAArch64LinuxMTEMemoryTagCoreFile.py
new file mode 100644
index 0000000000000..d16916cb1b23a
--- /dev/null
+++ b/lldb/test/API/linux/aarch64/mte_core_file/TestAArch64LinuxMTEMemoryTagCoreFile.py
@@ -0,0 +1,170 @@
+"""
+Test that memory tagging features work with Linux core files.
+"""
+
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+
+
+class AArch64LinuxMTEMemoryTagCoreFileTestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ NO_DEBUG_INFO_TESTCASE = True
+
+ MTE_BUF_ADDR = hex(0xffff82c74000)
+ BUF_ADDR = hex(0xffff82c73000)
+
+ @skipIfLLVMTargetMissing("AArch64")
+ def test_mte_tag_core_file_memory_region(self):
+ """ Test that memory regions are marked as tagged when there is a tag
+ segment in the core file. """
+ self.runCmd("target create --core core.mte")
+
+ # There should only be one tagged region.
+ self.runCmd("memory region --all")
+ got = self.res.GetOutput()
+ found_tagged_region = False
+
+ for line in got.splitlines():
+ if "memory tagging: enabled" in line:
+ if found_tagged_region:
+ self.fail("Expected only one tagged region.")
+ found_tagged_region = True
+
+ self.assertTrue(found_tagged_region, "Did not find a tagged memory region.")
+
+ # mte_buf is tagged, buf is not.
+ tagged = "memory tagging: enabled"
+ self.expect("memory region {}".format(self.MTE_BUF_ADDR),
+ patterns=[tagged])
+ self.expect("memory region {}".format(self.BUF_ADDR),
+ patterns=[tagged], matching=False)
+
+ @skipIfLLVMTargetMissing("AArch64")
+ def test_mte_tag_core_file_tag_write(self):
+ """ Test that "memory tag write" does not work with core files
+ as they are read only. """
+ self.runCmd("target create --core core.mte")
+
+ self.expect("memory tag write {} 1".format(self.MTE_BUF_ADDR), error=True,
+ patterns=["error: elf-core does not support writing memory tags"])
+
+ @skipIfLLVMTargetMissing("AArch64")
+ def test_mte_tag_core_file_tag_read(self):
+ """ Test that "memory tag read" works with core files."""
+ self.runCmd("target create --core core.mte")
+
+ # Tags are packed 2 per byte meaning that in addition to granule alignment
+ # there is also 2 x granule alignment going on.
+
+ # All input validation should work as normal.
+ not_tagged_pattern = ("error: Address range 0x[A-Fa-f0-9]+:0x[A-Fa-f0-9]+ "
+ "is not in a memory tagged region")
+ self.expect("memory tag read {}".format(self.BUF_ADDR),
+ error=True, patterns=[not_tagged_pattern])
+ # The first part of this range is not tagged.
+ self.expect("memory tag read {addr}-16 {addr}+16".format(
+ addr=self.MTE_BUF_ADDR), error=True,
+ patterns=[not_tagged_pattern])
+ # The last part of this range is not tagged.
+ self.expect("memory tag read {addr}+4096-16 {addr}+4096+16".format(
+ addr=self.MTE_BUF_ADDR), error=True,
+ patterns=[not_tagged_pattern])
+
+ self.expect("memory tag read {addr}+16 {addr}".format(
+ addr=self.MTE_BUF_ADDR), error=True,
+ patterns=["error: End address \(0x[A-Fa-f0-9]+\) "
+ "must be greater than the start address "
+ "\(0x[A-Fa-f0-9]+\)"])
+
+ # The simplest scenario. 2 granules means 1 byte of packed tags
+ # with no realignment required.
+ self.expect("memory tag read {addr} {addr}+32".format(
+ addr=self.MTE_BUF_ADDR),
+ patterns=[
+ "Allocation tags:\n"
+ "\[0x[A-Fa-f0-9]+00, 0x[A-Fa-f0-9]+10\): 0x0\n"
+ "\[0x[A-Fa-f0-9]+10, 0x[A-Fa-f0-9]+20\): 0x1 \(mismatch\)$"])
+
+ # Here we want just one tag so must use half of the first byte.
+ # (start is aligned length is not)
+ self.expect("memory tag read {addr} {addr}+16".format(
+ addr=self.MTE_BUF_ADDR),
+ patterns=[
+ "Allocation tags:\n"
+ "\[0x[A-Fa-f0-9]+00, 0x[A-Fa-f0-9]+10\): 0x0$"])
+ # Get the other half of the first byte.
+ # (end is aligned start is not)
+ self.expect("memory tag read {addr}+16 {addr}+32".format(
+ addr=self.MTE_BUF_ADDR),
+ patterns=[
+ "Allocation tags:\n"
+ "\[0x[A-Fa-f0-9]+10, 0x[A-Fa-f0-9]+20\): 0x1 \(mismatch\)$"])
+
+ # Same thing but with a starting range > 1 granule.
+ self.expect("memory tag read {addr} {addr}+48".format(
+ addr=self.MTE_BUF_ADDR),
+ patterns=[
+ "Allocation tags:\n"
+ "\[0x[A-Fa-f0-9]+00, 0x[A-Fa-f0-9]+10\): 0x0\n"
+ "\[0x[A-Fa-f0-9]+10, 0x[A-Fa-f0-9]+20\): 0x1 \(mismatch\)\n"
+ "\[0x[A-Fa-f0-9]+20, 0x[A-Fa-f0-9]+30\): 0x2 \(mismatch\)$"])
+ self.expect("memory tag read {addr}+16 {addr}+64".format(
+ addr=self.MTE_BUF_ADDR),
+ patterns=[
+ "Allocation tags:\n"
+ "\[0x[A-Fa-f0-9]+10, 0x[A-Fa-f0-9]+20\): 0x1 \(mismatch\)\n"
+ "\[0x[A-Fa-f0-9]+20, 0x[A-Fa-f0-9]+30\): 0x2 \(mismatch\)\n"
+ "\[0x[A-Fa-f0-9]+30, 0x[A-Fa-f0-9]+40\): 0x3 \(mismatch\)$"])
+ # Here both start and end are unaligned.
+ self.expect("memory tag read {addr}+16 {addr}+80".format(
+ addr=self.MTE_BUF_ADDR),
+ patterns=[
+ "Allocation tags:\n"
+ "\[0x[A-Fa-f0-9]+10, 0x[A-Fa-f0-9]+20\): 0x1 \(mismatch\)\n"
+ "\[0x[A-Fa-f0-9]+20, 0x[A-Fa-f0-9]+30\): 0x2 \(mismatch\)\n"
+ "\[0x[A-Fa-f0-9]+30, 0x[A-Fa-f0-9]+40\): 0x3 \(mismatch\)\n"
+ "\[0x[A-Fa-f0-9]+40, 0x[A-Fa-f0-9]+50\): 0x4 \(mismatch\)$"])
+
+ # For the intial alignment of start/end to granule boundaries the tag manager
+ # is used, so this reads 1 tag as it would normally.
+ self.expect("memory tag read {addr} {addr}+1".format(
+ addr=self.MTE_BUF_ADDR),
+ patterns=[
+ "Allocation tags:\n"
+ "\[0x[A-Fa-f0-9]+00, 0x[A-Fa-f0-9]+10\): 0x0$"])
+
+ # This range is aligned to granules as mte_buf to mte_buf+32 so the result
+ # should be 2 granules.
+ self.expect("memory tag read {addr} {addr}+17".format(
+ addr=self.MTE_BUF_ADDR),
+ patterns=[
+ "Allocation tags:\n"
+ "\[0x[A-Fa-f0-9]+00, 0x[A-Fa-f0-9]+10\): 0x0\n"
+ "\[0x[A-Fa-f0-9]+10, 0x[A-Fa-f0-9]+20\): 0x1 \(mismatch\)$"])
+
+ # Alignment of this range causes it to become unaligned to 2*granule boundaries.
+ self.expect("memory tag read {addr} {addr}+33".format(
+ addr=self.MTE_BUF_ADDR),
+ patterns=[
+ "Allocation tags:\n"
+ "\[0x[A-Fa-f0-9]+00, 0x[A-Fa-f0-9]+10\): 0x0\n"
+ "\[0x[A-Fa-f0-9]+10, 0x[A-Fa-f0-9]+20\): 0x1 \(mismatch\)\n",
+ "\[0x[A-Fa-f0-9]+20, 0x[A-Fa-f0-9]+30\): 0x2 \(mismatch\)$"])
+
+ @skipIfLLVMTargetMissing("AArch64")
+ def test_mte_commands_no_mte(self):
+ """ Test that memory tagging commands fail on an AArch64 corefile without
+ any tag segments."""
+
+ self.runCmd("target create --core core.nomte")
+
+ self.expect("memory tag read 0 1",
+ substrs=["error: Process does not support memory tagging"], error=True)
+ # Note that this tells you memory tagging is not supported at all, versus
+ # the MTE core file which does support it but does not allow writing tags.
+ self.expect("memory tag write 0 1",
+ substrs=["error: Process does not support memory tagging"], error=True)
diff --git a/lldb/test/API/linux/aarch64/mte_core_file/core.mte b/lldb/test/API/linux/aarch64/mte_core_file/core.mte
new file mode 100644
index 0000000000000..84a3266667e77
Binary files /dev/null and b/lldb/test/API/linux/aarch64/mte_core_file/core.mte
diff er
diff --git a/lldb/test/API/linux/aarch64/mte_core_file/core.nomte b/lldb/test/API/linux/aarch64/mte_core_file/core.nomte
new file mode 100644
index 0000000000000..201f2880e6dc2
Binary files /dev/null and b/lldb/test/API/linux/aarch64/mte_core_file/core.nomte
diff er
diff --git a/lldb/test/API/linux/aarch64/mte_core_file/main.c b/lldb/test/API/linux/aarch64/mte_core_file/main.c
new file mode 100644
index 0000000000000..89027e0ea75d2
--- /dev/null
+++ b/lldb/test/API/linux/aarch64/mte_core_file/main.c
@@ -0,0 +1,78 @@
+// Program to generate core files to test MTE tag features.
+//
+// This file uses ACLE intrinsics as detailed in:
+// https://developer.arm.com/documentation/101028/0012/10--Memory-tagging-intrinsics?lang=en
+//
+// Compile with:
+// <gcc or clang> -march=armv8.5-a+memtag -g main.c -o a.out.mte
+// <gcc or clang> -march=armv8.5-a+memtag -g main.c -DNO_MTE -o a.out.nomte
+//
+// /proc/self/coredump_filter was set to 2 when the core files were made.
+
+#include <arm_acle.h>
+#include <asm/mman.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <sys/prctl.h>
+#include <unistd.h>
+
+int main(int argc, char const *argv[]) {
+#ifdef NO_MTE
+ *(char *)(0) = 0;
+#endif
+
+ if (prctl(PR_SET_TAGGED_ADDR_CTRL,
+ PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_SYNC |
+ // Allow all tags to be generated by the addg
+ // instruction __arm_mte_increment_tag produces.
+ (0xffff << PR_MTE_TAG_SHIFT),
+ 0, 0, 0)) {
+ return 1;
+ }
+
+ size_t page_size = sysconf(_SC_PAGESIZE);
+ char *mte_buf = mmap(0, page_size, PROT_READ | PROT_WRITE | PROT_MTE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (!mte_buf)
+ return 1;
+
+ printf("mte_buf: %p\n", mte_buf);
+
+ // Allocate some untagged memory before the tagged memory.
+ char *buf = mmap(0, page_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (!buf)
+ return 1;
+
+ printf("buf: %p\n", buf);
+
+ // This write means that the memory for buf is included in the corefile.
+ // So we can read from the end of it into mte_buf during the test.
+ *buf = 1;
+
+ // These must be next to each other for the tests to work.
+ // <high address>
+ // mte_buf
+ // buf
+ // <low address>
+ if ((mte_buf - buf) != page_size) {
+ return 1;
+ }
+
+ // Set incrementing tags until end of the page.
+ char *tagged_ptr = mte_buf;
+ // This ignores tag bits when subtracting the addresses.
+ while (__arm_mte_ptr
diff (tagged_ptr, mte_buf) < page_size) {
+ // Set the allocation tag for this location.
+ __arm_mte_set_tag(tagged_ptr);
+ // + 16 for 16 byte granules.
+ // Earlier we allowed all tag values, so this will give us an
+ // incrementing pattern 0-0xF wrapping back to 0.
+ tagged_ptr = __arm_mte_increment_tag(tagged_ptr + 16, 1);
+ }
+
+ // Will fault because logical tag 0 != allocation tag 1.
+ *(mte_buf + 16) = 1;
+
+ return 0;
+}
diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst
index 193898a4c31c8..3b374e2c613dd 100644
--- a/llvm/docs/ReleaseNotes.rst
+++ b/llvm/docs/ReleaseNotes.rst
@@ -306,6 +306,8 @@ Changes to LLDB
locations. This prevents us reading locations multiple times, or not
writing out new values if the addresses have
diff erent non-address bits.
+* LLDB now supports reading memory tags from AArch64 Linux core files.
+
Changes to Sanitizers
---------------------
diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h
index fb74834bb57d9..a0bb50db8c544 100644
--- a/llvm/include/llvm/BinaryFormat/ELF.h
+++ b/llvm/include/llvm/BinaryFormat/ELF.h
@@ -1386,6 +1386,8 @@ enum {
// These all contain stack unwind tables.
PT_ARM_EXIDX = 0x70000001,
PT_ARM_UNWIND = 0x70000001,
+ // MTE memory tag segment type
+ PT_AARCH64_MEMTAG_MTE = 0x70000002,
// MIPS program header types.
PT_MIPS_REGINFO = 0x70000000, // Register usage information.
More information about the lldb-commits
mailing list