Skip to content

Commit dc00e19

Browse files
committed
[lldb] Add "memory tag write" --end-addr option
The default mode of "memory tag write" is to calculate the range from the start address and the number of tags given. (just like "memory write" does) (lldb) memory tag write mte_buf 1 2 (lldb) memory tag read mte_buf mte_buf+48 Logical tag: 0x0 Allocation tags: [0xfffff7ff9000, 0xfffff7ff9010): 0x1 [0xfffff7ff9010, 0xfffff7ff9020): 0x2 [0xfffff7ff9020, 0xfffff7ff9030): 0x0 This new option allows you to set an end address and have the tags repeat until that point. (lldb) memory tag write mte_buf 1 2 --end-addr mte_buf+64 (lldb) memory tag read mte_buf mte_buf+80 Logical tag: 0x0 Allocation tags: [0xfffff7ff9000, 0xfffff7ff9010): 0x1 [0xfffff7ff9010, 0xfffff7ff9020): 0x2 [0xfffff7ff9020, 0xfffff7ff9030): 0x1 [0xfffff7ff9030, 0xfffff7ff9040): 0x2 [0xfffff7ff9040, 0xfffff7ff9050): 0x0 This is implemented using the QMemTags packet previously added. We skip validating the number of tags in lldb and send them on to lldb-server, which repeats them as needed. Apart from the number of tags, all the other client side checks remain. Tag values, memory range must be tagged, etc. Reviewed By: omjavaid Differential Revision: https://reviews.llvm.org/D105183 (cherry picked from commit 6eded00)
1 parent 45d9885 commit dc00e19

File tree

3 files changed

+126
-5
lines changed

3 files changed

+126
-5
lines changed

lldb/source/Commands/CommandObjectMemoryTag.cpp

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "CommandObjectMemoryTag.h"
10+
#include "lldb/Host/OptionParser.h"
1011
#include "lldb/Interpreter/CommandReturnObject.h"
1112
#include "lldb/Interpreter/OptionArgParser.h"
13+
#include "lldb/Interpreter/OptionGroupFormat.h"
14+
#include "lldb/Interpreter/OptionValueString.h"
1215
#include "lldb/Target/Process.h"
1316

1417
using namespace lldb;
@@ -120,23 +123,64 @@ class CommandObjectMemoryTagRead : public CommandObjectParsed {
120123

121124
class CommandObjectMemoryTagWrite : public CommandObjectParsed {
122125
public:
126+
class OptionGroupTagWrite : public OptionGroup {
127+
public:
128+
OptionGroupTagWrite() : OptionGroup(), m_end_addr(LLDB_INVALID_ADDRESS) {}
129+
130+
~OptionGroupTagWrite() override = default;
131+
132+
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
133+
return llvm::makeArrayRef(g_memory_tag_write_options);
134+
}
135+
136+
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
137+
ExecutionContext *execution_context) override {
138+
Status status;
139+
const int short_option =
140+
g_memory_tag_write_options[option_idx].short_option;
141+
142+
switch (short_option) {
143+
case 'e':
144+
m_end_addr = OptionArgParser::ToAddress(execution_context, option_value,
145+
LLDB_INVALID_ADDRESS, &status);
146+
break;
147+
default:
148+
llvm_unreachable("Unimplemented option");
149+
}
150+
151+
return status;
152+
}
153+
154+
void OptionParsingStarting(ExecutionContext *execution_context) override {
155+
m_end_addr = LLDB_INVALID_ADDRESS;
156+
}
157+
158+
lldb::addr_t m_end_addr;
159+
};
160+
123161
CommandObjectMemoryTagWrite(CommandInterpreter &interpreter)
124162
: CommandObjectParsed(interpreter, "tag",
125163
"Write memory tags starting from the granule that "
126164
"contains the given address.",
127165
nullptr,
128166
eCommandRequiresTarget | eCommandRequiresProcess |
129-
eCommandProcessMustBePaused) {
167+
eCommandProcessMustBePaused),
168+
m_option_group(), m_tag_write_options() {
130169
// Address
131170
m_arguments.push_back(
132171
CommandArgumentEntry{CommandArgumentData(eArgTypeAddressOrExpression)});
133172
// One or more tag values
134173
m_arguments.push_back(CommandArgumentEntry{
135174
CommandArgumentData(eArgTypeValue, eArgRepeatPlus)});
175+
176+
m_option_group.Append(&m_tag_write_options);
177+
m_option_group.Finalize();
136178
}
137179

138180
~CommandObjectMemoryTagWrite() override = default;
139181

182+
Options *GetOptions() override { return &m_option_group; }
183+
140184
protected:
141185
bool DoExecute(Args &command, CommandReturnObject &result) override {
142186
if (command.GetArgumentCount() < 2) {
@@ -196,14 +240,24 @@ class CommandObjectMemoryTagWrite : public CommandObjectParsed {
196240
tag_manager->ExpandToGranule(MemoryTagManager::TagRange(start_addr, 1))
197241
.GetRangeBase();
198242

243+
lldb::addr_t end_addr = 0;
244+
// When you have an end address you want to align the range like tag read
245+
// does. Meaning, align the start down (which we've done) and align the end
246+
// up.
247+
if (m_tag_write_options.m_end_addr != LLDB_INVALID_ADDRESS)
248+
end_addr = m_tag_write_options.m_end_addr;
249+
else
250+
// Without an end address assume number of tags matches number of granules
251+
// to write to
252+
end_addr =
253+
aligned_start_addr + (tags.size() * tag_manager->GetGranuleSize());
254+
199255
// Now we've aligned the start address so if we ask for another range
200256
// using the number of tags N, we'll get back a range that is also N
201257
// granules in size.
202258
llvm::Expected<MemoryTagManager::TagRange> tagged_range =
203-
tag_manager->MakeTaggedRange(
204-
aligned_start_addr,
205-
aligned_start_addr + (tags.size() * tag_manager->GetGranuleSize()),
206-
memory_regions);
259+
tag_manager->MakeTaggedRange(aligned_start_addr, end_addr,
260+
memory_regions);
207261

208262
if (!tagged_range) {
209263
result.SetError(Status(tagged_range.takeError()));
@@ -221,6 +275,9 @@ class CommandObjectMemoryTagWrite : public CommandObjectParsed {
221275
result.SetStatus(eReturnStatusSuccessFinishResult);
222276
return true;
223277
}
278+
279+
OptionGroupOptions m_option_group;
280+
OptionGroupTagWrite m_tag_write_options;
224281
};
225282

226283
CommandObjectMemoryTag::CommandObjectMemoryTag(CommandInterpreter &interpreter)

lldb/source/Commands/Options.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,14 @@ let Command = "memory write" in {
504504
Desc<"Start writing bytes from an offset within the input file.">;
505505
}
506506

507+
let Command = "memory tag write" in {
508+
def memory_write_end_addr : Option<"end-addr", "e">, Group<1>,
509+
Arg<"AddressOrExpression">, Desc<
510+
"Set tags for start address to end-addr, repeating tags as needed"
511+
" to cover the range. (instead of calculating the range from the"
512+
" number of tags given)">;
513+
}
514+
507515
let Command = "register read" in {
508516
def register_read_alternate : Option<"alternate", "A">,
509517
Desc<"Display register names using the alternate register name if there "

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

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,3 +216,59 @@ def test_mte_tag_write(self):
216216
self.expect("memory tag write mte_buf 99",
217217
patterns=["error: Found tag 0x63 which is > max MTE tag value of 0xf."],
218218
error=True)
219+
220+
# You can provide an end address and have lldb repeat the tags as needed
221+
# The range is checked in the same way it is for "memory tag read"
222+
self.expect("memory tag write mte_buf 9 -e",
223+
patterns=["error: last option requires an argument"],
224+
error=True)
225+
self.expect("memory tag write mte_buf 9 -e food",
226+
patterns=["error: address expression \"food\" evaluation failed"],
227+
error=True)
228+
self.expect("memory tag write mte_buf_2 9 --end-addr mte_buf_2",
229+
patterns=["error: End address \(0x[A-Fa-f0-9]+\) must be "
230+
"greater than the start address \(0x[A-Fa-f0-9]+\)"],
231+
error=True)
232+
self.expect("memory tag write mte_buf_2 9 --end-addr mte_buf_2-16",
233+
patterns=["error: End address \(0x[A-Fa-f0-9]+\) must be "
234+
"greater than the start address \(0x[A-Fa-f0-9]+\)"],
235+
error=True)
236+
self.expect("memory tag write mte_buf_2 9 --end-addr mte_buf_2+page_size+16",
237+
patterns=["error: Address range 0x[0-9A-fa-f]+00:0x[0-9A-Fa-f]+10 "
238+
"is not in a memory tagged region"],
239+
error=True)
240+
241+
# Tags are repeated across the range
242+
# For these we'll read one extra to make sure we don't over write
243+
self.expect("memory tag write mte_buf_2 4 5 --end-addr mte_buf_2+48")
244+
self.expect("memory tag read mte_buf_2 mte_buf_2+64",
245+
patterns=["Logical tag: 0x0\n"
246+
"Allocation tags:\n"
247+
"\[0x[0-9A-Fa-f]+00, 0x[0-9A-Fa-f]+10\): 0x4\n"
248+
"\[0x[0-9A-Fa-f]+10, 0x[0-9A-Fa-f]+20\): 0x5\n"
249+
"\[0x[0-9A-Fa-f]+20, 0x[0-9A-Fa-f]+30\): 0x4\n"
250+
"\[0x[0-9A-Fa-f]+30, 0x[0-9A-Fa-f]+40\): 0x0$"])
251+
252+
# Since this aligns like tag read does, the start is aligned down and the end up.
253+
# Meaning that start/end tells you the start/end granule that will be written.
254+
# This matters particularly if either are misaligned.
255+
256+
# Here start moves down so the final range is mte_buf_2 -> mte_buf_2+32
257+
self.expect("memory tag write mte_buf_2+8 6 -end-addr mte_buf_2+32")
258+
self.expect("memory tag read mte_buf_2 mte_buf_2+48",
259+
patterns=["Logical tag: 0x0\n"
260+
"Allocation tags:\n"
261+
"\[0x[0-9A-Fa-f]+00, 0x[0-9A-Fa-f]+10\): 0x6\n"
262+
"\[0x[0-9A-Fa-f]+10, 0x[0-9A-Fa-f]+20\): 0x6\n"
263+
"\[0x[0-9A-Fa-f]+20, 0x[0-9A-Fa-f]+30\): 0x4$"])
264+
265+
# If we do the same with a misaligned end, it also moves but upward.
266+
# The intial range is 2 granules but the final range is mte_buf_2 -> mte_buf_2+48
267+
self.expect("memory tag write mte_buf_2+8 3 -end-addr mte_buf_2+32+8")
268+
self.expect("memory tag read mte_buf_2 mte_buf_2+64",
269+
patterns=["Logical tag: 0x0\n"
270+
"Allocation tags:\n"
271+
"\[0x[0-9A-Fa-f]+00, 0x[0-9A-Fa-f]+10\): 0x3\n"
272+
"\[0x[0-9A-Fa-f]+10, 0x[0-9A-Fa-f]+20\): 0x3\n"
273+
"\[0x[0-9A-Fa-f]+20, 0x[0-9A-Fa-f]+30\): 0x3\n"
274+
"\[0x[0-9A-Fa-f]+30, 0x[0-9A-Fa-f]+40\): 0x0$"])

0 commit comments

Comments
 (0)