Skip to content

Commit 787f91b

Browse files
committed
[lldb] Remove non-address bits from addresses given to memory tag commands
Although the memory tag commands use a memory tag manager to handle addresses, that only removes the top byte. That top byte is 4 bits of memory tag and 4 free bits, which is more than it should strictly remove but that's how it is for now. There are other non-address bit uses like pointer authentication. To ensure the memory tag manager only has to deal with memory tags, use the ABI plugin to remove the rest. The tag access test has been updated to sign all the relevant pointers and require that we're running on a system with pointer authentication in addition to memory tagging. The pointers will look like: <4 bit user tag><4 bit memory tag><signature><bit virtual address> Note that there is currently no API for reading memory tags. It will also have to consider this when it arrives. Reviewed By: omjavaid Differential Revision: https://reviews.llvm.org/D117672
1 parent 585abe3 commit 787f91b

File tree

3 files changed

+39
-3
lines changed

3 files changed

+39
-3
lines changed

lldb/source/Commands/CommandObjectMemoryTag.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "lldb/Interpreter/OptionArgParser.h"
1313
#include "lldb/Interpreter/OptionGroupFormat.h"
1414
#include "lldb/Interpreter/OptionValueString.h"
15+
#include "lldb/Target/ABI.h"
1516
#include "lldb/Target/Process.h"
1617

1718
using namespace lldb;
@@ -85,6 +86,17 @@ class CommandObjectMemoryTagRead : public CommandObjectParsed {
8586
// If this fails the list of regions is cleared, so we don't need to read
8687
// the return status here.
8788
process->GetMemoryRegions(memory_regions);
89+
90+
lldb::addr_t logical_tag = tag_manager->GetLogicalTag(start_addr);
91+
92+
// The tag manager only removes tag bits. These addresses may include other
93+
// non-address bits that must also be ignored.
94+
ABISP abi = process->GetABI();
95+
if (abi) {
96+
start_addr = abi->FixDataAddress(start_addr);
97+
end_addr = abi->FixDataAddress(end_addr);
98+
}
99+
88100
llvm::Expected<MemoryTagManager::TagRange> tagged_range =
89101
tag_manager->MakeTaggedRange(start_addr, end_addr, memory_regions);
90102

@@ -101,7 +113,6 @@ class CommandObjectMemoryTagRead : public CommandObjectParsed {
101113
return false;
102114
}
103115

104-
lldb::addr_t logical_tag = tag_manager->GetLogicalTag(start_addr);
105116
result.AppendMessageWithFormatv("Logical tag: {0:x}", logical_tag);
106117
result.AppendMessage("Allocation tags:");
107118

@@ -231,6 +242,12 @@ class CommandObjectMemoryTagWrite : public CommandObjectParsed {
231242
// the return status here.
232243
process->GetMemoryRegions(memory_regions);
233244

245+
// The tag manager only removes tag bits. These addresses may include other
246+
// non-address bits that must also be ignored.
247+
ABISP abi = process->GetABI();
248+
if (abi)
249+
start_addr = abi->FixDataAddress(start_addr);
250+
234251
// We have to assume start_addr is not granule aligned.
235252
// So if we simply made a range:
236253
// (start_addr, start_addr + (N * granule_size))
@@ -254,6 +271,10 @@ class CommandObjectMemoryTagWrite : public CommandObjectParsed {
254271
end_addr =
255272
aligned_start_addr + (tags.size() * tag_manager->GetGranuleSize());
256273

274+
// Remove non-address bits that aren't memory tags
275+
if (abi)
276+
end_addr = abi->FixDataAddress(end_addr);
277+
257278
// Now we've aligned the start address so if we ask for another range
258279
// using the number of tags N, we'll get back a range that is also N
259280
// granules in size.

lldb/test/API/linux/aarch64/mte_tag_access/TestAArch64LinuxMTEMemoryTagAccess.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ def setup_mte_test(self):
2020
if not self.isAArch64MTE():
2121
self.skipTest('Target must support MTE.')
2222

23+
# Required to check that commands remove non-address bits
24+
# other than the memory tags.
25+
if not self.isAArch64PAuth():
26+
self.skipTest('Target must support pointer authentication')
27+
2328
self.build()
2429
self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
2530

lldb/test/API/linux/aarch64/mte_tag_access/main.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,9 @@ int main(int argc, char const *argv[]) {
7171
// tag
7272
char *mte_buf_alt_tag = __arm_mte_create_random_tag(mte_buf, ~(1 << 10));
7373

74-
// lldb should be removing the whole top byte, not just the tags.
75-
// So fill 63-60 with something non zero so we'll fail if we only remove tags.
74+
// The memory tag manager should be removing the whole top byte, not just the
75+
// tags. So fill 63-60 with something non zero so we'll fail if we only remove
76+
// tags.
7677
#define SET_TOP_NIBBLE(ptr, value) \
7778
(char *)((size_t)(ptr) | ((size_t)((value)&0xf) << 60))
7879
// mte_buf_alt_tag's nibble > mte_buf to check that lldb isn't just removing
@@ -82,6 +83,15 @@ int main(int argc, char const *argv[]) {
8283
mte_buf_2 = SET_TOP_NIBBLE(mte_buf_2, 0xC);
8384
mte_read_only = SET_TOP_NIBBLE(mte_read_only, 0xD);
8485

86+
// The top level commands should be removing all non-address bits, including
87+
// pointer signatures. This signs ptr with PAC key A. That signature goes
88+
// in some bits other than the top byte.
89+
#define sign_ptr(ptr) __asm__ __volatile__("pacdza %0" : "=r"(ptr) : "r"(ptr))
90+
sign_ptr(mte_buf);
91+
sign_ptr(mte_buf_alt_tag);
92+
sign_ptr(mte_buf_2);
93+
sign_ptr(mte_read_only);
94+
8595
// Breakpoint here
8696
return 0;
8797
}

0 commit comments

Comments
 (0)