Skip to content

Commit d046fb6

Browse files
committed
[lldb][AArch64] Refactor memory tag range handling
Previously GetMemoryTagManager checked many things in one: * architecture supports memory tagging * process supports memory tagging * memory range isn't inverted * memory range is all tagged Since writing follow up patches for tag writing (in review at the moment) it has become clear that this gets unwieldy once we add the features needed for that. It also implies that the memory tag manager is tied to the range you used to request it with but it is not. It's a per process object. Instead: * GetMemoryTagManager just checks architecture and process. * Then the MemoryTagManager can later be asked to check a memory range. This is better because: * We don't imply that range and manager are tied together. * A slightly diferent range calculation for tag writing doesn't add more code to Process. * Range checking code can now be unit tested. Reviewed By: omjavaid Differential Revision: https://reviews.llvm.org/D105630
1 parent 239d01f commit d046fb6

File tree

7 files changed

+230
-83
lines changed

7 files changed

+230
-83
lines changed

lldb/include/lldb/Target/MemoryTagManager.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#ifndef LLDB_TARGET_MEMORYTAGMANAGER_H
1010
#define LLDB_TARGET_MEMORYTAGMANAGER_H
1111

12+
#include "lldb/Target/MemoryRegionInfo.h"
1213
#include "lldb/Utility/RangeMap.h"
1314
#include "lldb/lldb-private.h"
1415
#include "llvm/Support/Error.h"
@@ -57,6 +58,20 @@ class MemoryTagManager {
5758
// expanded to 2 granules.
5859
virtual TagRange ExpandToGranule(TagRange range) const = 0;
5960

61+
// Given a range addr to end_addr, check that:
62+
// * end_addr >= addr (when memory tags are removed)
63+
// * the granule aligned range is completely covered by tagged memory
64+
// (which may include one or more memory regions)
65+
//
66+
// If so, return a modified range which will have been expanded
67+
// to be granule aligned.
68+
//
69+
// Tags in the input addresses are ignored and not present
70+
// in the returned range.
71+
virtual llvm::Expected<TagRange> MakeTaggedRange(
72+
lldb::addr_t addr, lldb::addr_t end_addr,
73+
const lldb_private::MemoryRegionInfos &memory_regions) const = 0;
74+
6075
// Return the type value to use in GDB protocol qMemTags packets to read
6176
// allocation tags. This is named "Allocation" specifically because the spec
6277
// allows for logical tags to be read the same way, though we do not use that.

lldb/include/lldb/Target/Process.h

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1709,30 +1709,19 @@ class Process : public std::enable_shared_from_this<Process>,
17091709
lldb::addr_t CallocateMemory(size_t size, uint32_t permissions,
17101710
Status &error);
17111711

1712-
/// If the address range given is in a memory tagged range and this
1713-
/// architecture and process supports memory tagging, return a tag
1712+
/// If this architecture and process supports memory tagging, return a tag
17141713
/// manager that can be used to maniupulate those memory tags.
1715-
/// Tags present in the addresses given are ignored.
1716-
///
1717-
/// \param[in] addr
1718-
/// Start of memory range.
1719-
///
1720-
/// \param[in] end_addr
1721-
/// End of the memory range. Where end is one beyond the last byte to be
1722-
/// included.
17231714
///
17241715
/// \return
17251716
/// Either a valid pointer to a tag manager or an error describing why one
17261717
/// could not be provided.
1727-
llvm::Expected<const MemoryTagManager *>
1728-
GetMemoryTagManager(lldb::addr_t addr, lldb::addr_t end_addr);
1718+
llvm::Expected<const MemoryTagManager *> GetMemoryTagManager();
17291719

1730-
/// Expands the range addr to addr+len to align with granule boundaries and
1731-
/// then calls DoReadMemoryTags to do the target specific operations.
1732-
/// Tags are returned unpacked so can be used without conversion.
1720+
/// Read memory tags for the range addr to addr+len. It is assumed
1721+
/// that this range has already been granule aligned.
1722+
/// (see MemoryTagManager::MakeTaggedRange)
17331723
///
1734-
/// \param[in] tag_manager
1735-
/// The tag manager to get memory tagging information from.
1724+
/// This calls DoReadMemoryTags to do the target specific operations.
17361725
///
17371726
/// \param[in] addr
17381727
/// Start of memory range to read tags for.
@@ -1741,11 +1730,12 @@ class Process : public std::enable_shared_from_this<Process>,
17411730
/// Length of memory range to read tags for (in bytes).
17421731
///
17431732
/// \return
1744-
/// Either the unpacked tags or an error describing a failure to read
1745-
/// or unpack them.
1746-
llvm::Expected<std::vector<lldb::addr_t>>
1747-
ReadMemoryTags(const MemoryTagManager *tag_manager, lldb::addr_t addr,
1748-
size_t len);
1733+
/// If this architecture or process does not support memory tagging,
1734+
/// an error saying so.
1735+
/// If it does, either the memory tags or an error describing a
1736+
/// failure to read or unpack them.
1737+
llvm::Expected<std::vector<lldb::addr_t>> ReadMemoryTags(lldb::addr_t addr,
1738+
size_t len);
17491739

17501740
/// Resolve dynamically loaded indirect functions.
17511741
///

lldb/source/Commands/CommandObjectMemoryTag.cpp

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,17 +68,29 @@ class CommandObjectMemoryTagRead : public CommandObjectParsed {
6868

6969
Process *process = m_exe_ctx.GetProcessPtr();
7070
llvm::Expected<const MemoryTagManager *> tag_manager_or_err =
71-
process->GetMemoryTagManager(start_addr, end_addr);
71+
process->GetMemoryTagManager();
7272

7373
if (!tag_manager_or_err) {
7474
result.SetError(Status(tag_manager_or_err.takeError()));
7575
return false;
7676
}
7777

7878
const MemoryTagManager *tag_manager = *tag_manager_or_err;
79-
ptrdiff_t len = tag_manager->AddressDiff(end_addr, start_addr);
80-
llvm::Expected<std::vector<lldb::addr_t>> tags =
81-
process->ReadMemoryTags(tag_manager, start_addr, len);
79+
80+
MemoryRegionInfos memory_regions;
81+
// If this fails the list of regions is cleared, so we don't need to read
82+
// the return status here.
83+
process->GetMemoryRegions(memory_regions);
84+
llvm::Expected<MemoryTagManager::TagRange> tagged_range =
85+
tag_manager->MakeTaggedRange(start_addr, end_addr, memory_regions);
86+
87+
if (!tagged_range) {
88+
result.SetError(Status(tagged_range.takeError()));
89+
return false;
90+
}
91+
92+
llvm::Expected<std::vector<lldb::addr_t>> tags = process->ReadMemoryTags(
93+
tagged_range->GetRangeBase(), tagged_range->GetByteSize());
8294

8395
if (!tags) {
8496
result.SetError(Status(tags.takeError()));
@@ -89,8 +101,7 @@ class CommandObjectMemoryTagRead : public CommandObjectParsed {
89101
tag_manager->GetLogicalTag(start_addr));
90102
result.AppendMessage("Allocation tags:");
91103

92-
MemoryTagManager::TagRange initial_range(start_addr, len);
93-
addr_t addr = tag_manager->ExpandToGranule(initial_range).GetRangeBase();
104+
addr_t addr = tagged_range->GetRangeBase();
94105
for (auto tag : *tags) {
95106
addr_t next_addr = addr + tag_manager->GetGranuleSize();
96107
// Showing tagged adresses here until we have non address bit handling

lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,63 @@ MemoryTagManagerAArch64MTE::ExpandToGranule(TagRange range) const {
6666
return TagRange(new_start, new_len);
6767
}
6868

69+
llvm::Expected<MemoryTagManager::TagRange>
70+
MemoryTagManagerAArch64MTE::MakeTaggedRange(
71+
lldb::addr_t addr, lldb::addr_t end_addr,
72+
const lldb_private::MemoryRegionInfos &memory_regions) const {
73+
// First check that the range is not inverted.
74+
// We must remove tags here otherwise an address with a higher
75+
// tag value will always be > the other.
76+
ptrdiff_t len = AddressDiff(end_addr, addr);
77+
if (len <= 0) {
78+
return llvm::createStringError(
79+
llvm::inconvertibleErrorCode(),
80+
"End address (0x%" PRIx64
81+
") must be greater than the start address (0x%" PRIx64 ")",
82+
end_addr, addr);
83+
}
84+
85+
// Region addresses will not have memory tags. So when searching
86+
// we must use an untagged address.
87+
MemoryRegionInfo::RangeType tag_range(RemoveNonAddressBits(addr), len);
88+
tag_range = ExpandToGranule(tag_range);
89+
90+
// Make a copy so we can use the original for errors and the final return.
91+
MemoryRegionInfo::RangeType remaining_range(tag_range);
92+
93+
// While there are parts of the range that don't have a matching tagged memory
94+
// region
95+
while (remaining_range.IsValid()) {
96+
// Search for a region that contains the start of the range
97+
MemoryRegionInfos::const_iterator region = std::find_if(
98+
memory_regions.cbegin(), memory_regions.cend(),
99+
[&remaining_range](const MemoryRegionInfo &region) {
100+
return region.GetRange().Contains(remaining_range.GetRangeBase());
101+
});
102+
103+
if (region == memory_regions.cend() ||
104+
region->GetMemoryTagged() != MemoryRegionInfo::eYes) {
105+
// Some part of this range is untagged (or unmapped) so error
106+
return llvm::createStringError(llvm::inconvertibleErrorCode(),
107+
"Address range 0x%" PRIx64 ":0x%" PRIx64
108+
" is not in a memory tagged region",
109+
tag_range.GetRangeBase(),
110+
tag_range.GetRangeEnd());
111+
}
112+
113+
// We've found some part of the range so remove that part and continue
114+
// searching for the rest. Moving the base "slides" the range so we need to
115+
// save/restore the original end. If old_end is less than the new base, the
116+
// range will be set to have 0 size and we'll exit the while.
117+
lldb::addr_t old_end = remaining_range.GetRangeEnd();
118+
remaining_range.SetRangeBase(region->GetRange().GetRangeEnd());
119+
remaining_range.SetRangeEnd(old_end);
120+
}
121+
122+
// Every part of the range is contained within a tagged memory region.
123+
return tag_range;
124+
}
125+
69126
llvm::Expected<std::vector<lldb::addr_t>>
70127
MemoryTagManagerAArch64MTE::UnpackTagsData(const std::vector<uint8_t> &tags,
71128
size_t granules) const {

lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ class MemoryTagManagerAArch64MTE : public MemoryTagManager {
3232

3333
TagRange ExpandToGranule(TagRange range) const override;
3434

35+
llvm::Expected<TagRange> MakeTaggedRange(
36+
lldb::addr_t addr, lldb::addr_t end_addr,
37+
const lldb_private::MemoryRegionInfos &memory_regions) const override;
38+
3539
llvm::Expected<std::vector<lldb::addr_t>>
3640
UnpackTagsData(const std::vector<uint8_t> &tags,
3741
size_t granules) const override;

lldb/source/Target/Process.cpp

Lines changed: 10 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -6067,8 +6067,7 @@ bool Process::CallVoidArgVoidPtrReturn(const Address *address,
60676067
return false;
60686068
}
60696069

6070-
llvm::Expected<const MemoryTagManager *>
6071-
Process::GetMemoryTagManager(lldb::addr_t addr, lldb::addr_t end_addr) {
6070+
llvm::Expected<const MemoryTagManager *> Process::GetMemoryTagManager() {
60726071
Architecture *arch = GetTarget().GetArchitecturePlugin();
60736072
const MemoryTagManager *tag_manager =
60746073
arch ? arch->GetMemoryTagManager() : nullptr;
@@ -6084,66 +6083,22 @@ Process::GetMemoryTagManager(lldb::addr_t addr, lldb::addr_t end_addr) {
60846083
"Process does not support memory tagging");
60856084
}
60866085

6087-
ptrdiff_t len = tag_manager->AddressDiff(end_addr, addr);
6088-
if (len <= 0) {
6089-
return llvm::createStringError(
6090-
llvm::inconvertibleErrorCode(),
6091-
"End address (0x%" PRIx64
6092-
") must be greater than the start address (0x%" PRIx64 ")",
6093-
end_addr, addr);
6094-
}
6095-
6096-
// Region lookup is not address size aware so mask the address
6097-
MemoryRegionInfo::RangeType tag_range(tag_manager->RemoveNonAddressBits(addr),
6098-
len);
6099-
tag_range = tag_manager->ExpandToGranule(tag_range);
6100-
6101-
// Make a copy so we can use the original range in errors
6102-
MemoryRegionInfo::RangeType remaining_range(tag_range);
6103-
6104-
// While we haven't found a matching memory region for some of the range
6105-
while (remaining_range.IsValid()) {
6106-
MemoryRegionInfo region;
6107-
Status status = GetMemoryRegionInfo(remaining_range.GetRangeBase(), region);
6108-
6109-
if (status.Fail() || region.GetMemoryTagged() != MemoryRegionInfo::eYes) {
6110-
return llvm::createStringError(
6111-
llvm::inconvertibleErrorCode(),
6112-
"Address range 0x%lx:0x%lx is not in a memory tagged region",
6113-
tag_range.GetRangeBase(), tag_range.GetRangeEnd());
6114-
}
6115-
6116-
if (region.GetRange().GetRangeEnd() >= remaining_range.GetRangeEnd()) {
6117-
// We've found a region for the whole range or the last piece of a range
6118-
remaining_range.SetByteSize(0);
6119-
} else {
6120-
// We've found some part of the range, look for the rest
6121-
remaining_range.SetRangeBase(region.GetRange().GetRangeEnd());
6122-
}
6123-
}
6124-
61256086
return tag_manager;
61266087
}
61276088

61286089
llvm::Expected<std::vector<lldb::addr_t>>
6129-
Process::ReadMemoryTags(const MemoryTagManager *tag_manager, lldb::addr_t addr,
6130-
size_t len) {
6131-
if (!tag_manager) {
6132-
return llvm::createStringError(
6133-
llvm::inconvertibleErrorCode(),
6134-
"A memory tag manager is required for reading memory tags.");
6135-
}
6136-
6137-
MemoryTagManager::TagRange range(tag_manager->RemoveNonAddressBits(addr),
6138-
len);
6139-
range = tag_manager->ExpandToGranule(range);
6090+
Process::ReadMemoryTags(lldb::addr_t addr, size_t len) {
6091+
llvm::Expected<const MemoryTagManager *> tag_manager_or_err =
6092+
GetMemoryTagManager();
6093+
if (!tag_manager_or_err)
6094+
return tag_manager_or_err.takeError();
61406095

6096+
const MemoryTagManager *tag_manager = *tag_manager_or_err;
61416097
llvm::Expected<std::vector<uint8_t>> tag_data =
6142-
DoReadMemoryTags(range.GetRangeBase(), range.GetByteSize(),
6143-
tag_manager->GetAllocationTagType());
6098+
DoReadMemoryTags(addr, len, tag_manager->GetAllocationTagType());
61446099
if (!tag_data)
61456100
return tag_data.takeError();
61466101

6147-
return tag_manager->UnpackTagsData(
6148-
*tag_data, range.GetByteSize() / tag_manager->GetGranuleSize());
6102+
return tag_manager->UnpackTagsData(*tag_data,
6103+
len / tag_manager->GetGranuleSize());
61496104
}

0 commit comments

Comments
 (0)