forked from OSchip/llvm-project
[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
This commit is contained in:
parent
4075a811ad
commit
2f9fa9ef53
|
@ -1715,8 +1715,8 @@ public:
|
|||
/// 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)
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -86,6 +86,11 @@ public:
|
|||
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 @@ protected:
|
|||
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 @@ private:
|
|||
// 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 @@ private:
|
|||
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);
|
||||
|
|
|
@ -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)
|
Binary file not shown.
Binary file not shown.
|
@ -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_ptrdiff(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;
|
||||
}
|
|
@ -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 different non-address bits.
|
||||
|
||||
* LLDB now supports reading memory tags from AArch64 Linux core files.
|
||||
|
||||
Changes to Sanitizers
|
||||
---------------------
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue