1 //===-- CommandObjectMemoryTag.cpp ----------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "CommandObjectMemoryTag.h"
10 #include "lldb/Host/OptionParser.h"
11 #include "lldb/Interpreter/CommandOptionArgumentTable.h"
12 #include "lldb/Interpreter/CommandReturnObject.h"
13 #include "lldb/Interpreter/OptionArgParser.h"
14 #include "lldb/Interpreter/OptionGroupFormat.h"
15 #include "lldb/Interpreter/OptionValueString.h"
16 #include "lldb/Target/ABI.h"
17 #include "lldb/Target/Process.h"
20 using namespace lldb_private
;
22 #define LLDB_OPTIONS_memory_tag_read
23 #include "CommandOptions.inc"
25 class CommandObjectMemoryTagRead
: public CommandObjectParsed
{
27 CommandObjectMemoryTagRead(CommandInterpreter
&interpreter
)
28 : CommandObjectParsed(interpreter
, "tag",
29 "Read memory tags for the given range of memory."
30 " Mismatched tags will be marked.",
32 eCommandRequiresTarget
| eCommandRequiresProcess
|
33 eCommandProcessMustBePaused
) {
35 m_arguments
.push_back(
36 CommandArgumentEntry
{CommandArgumentData(eArgTypeAddressOrExpression
)});
37 // Optional end address
38 m_arguments
.push_back(CommandArgumentEntry
{
39 CommandArgumentData(eArgTypeAddressOrExpression
, eArgRepeatOptional
)});
42 ~CommandObjectMemoryTagRead() override
= default;
45 void DoExecute(Args
&command
, CommandReturnObject
&result
) override
{
46 if ((command
.GetArgumentCount() < 1) || (command
.GetArgumentCount() > 2)) {
48 "wrong number of arguments; expected at least <address-expression>, "
49 "at most <address-expression> <end-address-expression>");
54 addr_t start_addr
= OptionArgParser::ToRawAddress(
55 &m_exe_ctx
, command
[0].ref(), LLDB_INVALID_ADDRESS
, &error
);
56 if (start_addr
== LLDB_INVALID_ADDRESS
) {
57 result
.AppendErrorWithFormatv("Invalid address expression, {0}",
62 // Default 1 byte beyond start, rounds up to at most 1 granule later
63 addr_t end_addr
= start_addr
+ 1;
65 if (command
.GetArgumentCount() > 1) {
66 end_addr
= OptionArgParser::ToRawAddress(&m_exe_ctx
, command
[1].ref(),
67 LLDB_INVALID_ADDRESS
, &error
);
68 if (end_addr
== LLDB_INVALID_ADDRESS
) {
69 result
.AppendErrorWithFormatv("Invalid end address expression, {0}",
75 Process
*process
= m_exe_ctx
.GetProcessPtr();
76 llvm::Expected
<const MemoryTagManager
*> tag_manager_or_err
=
77 process
->GetMemoryTagManager();
79 if (!tag_manager_or_err
) {
80 result
.SetError(Status::FromError(tag_manager_or_err
.takeError()));
84 const MemoryTagManager
*tag_manager
= *tag_manager_or_err
;
86 MemoryRegionInfos memory_regions
;
87 // If this fails the list of regions is cleared, so we don't need to read
88 // the return status here.
89 process
->GetMemoryRegions(memory_regions
);
91 lldb::addr_t logical_tag
= tag_manager
->GetLogicalTag(start_addr
);
93 // The tag manager only removes tag bits. These addresses may include other
94 // non-address bits that must also be ignored.
95 ABISP abi
= process
->GetABI();
97 start_addr
= abi
->FixDataAddress(start_addr
);
98 end_addr
= abi
->FixDataAddress(end_addr
);
101 llvm::Expected
<MemoryTagManager::TagRange
> tagged_range
=
102 tag_manager
->MakeTaggedRange(start_addr
, end_addr
, memory_regions
);
105 result
.SetError(Status::FromError(tagged_range
.takeError()));
109 llvm::Expected
<std::vector
<lldb::addr_t
>> tags
= process
->ReadMemoryTags(
110 tagged_range
->GetRangeBase(), tagged_range
->GetByteSize());
113 result
.SetError(Status::FromError(tags
.takeError()));
117 result
.AppendMessageWithFormatv("Logical tag: {0:x}", logical_tag
);
118 result
.AppendMessage("Allocation tags:");
120 addr_t addr
= tagged_range
->GetRangeBase();
121 for (auto tag
: *tags
) {
122 addr_t next_addr
= addr
+ tag_manager
->GetGranuleSize();
123 // Showing tagged adresses here until we have non address bit handling
124 result
.AppendMessageWithFormatv("[{0:x}, {1:x}): {2:x}{3}", addr
,
126 logical_tag
== tag
? "" : " (mismatch)");
130 result
.SetStatus(eReturnStatusSuccessFinishResult
);
134 #define LLDB_OPTIONS_memory_tag_write
135 #include "CommandOptions.inc"
137 class CommandObjectMemoryTagWrite
: public CommandObjectParsed
{
139 class OptionGroupTagWrite
: public OptionGroup
{
141 OptionGroupTagWrite() = default;
143 ~OptionGroupTagWrite() override
= default;
145 llvm::ArrayRef
<OptionDefinition
> GetDefinitions() override
{
146 return llvm::ArrayRef(g_memory_tag_write_options
);
149 Status
SetOptionValue(uint32_t option_idx
, llvm::StringRef option_value
,
150 ExecutionContext
*execution_context
) override
{
152 const int short_option
=
153 g_memory_tag_write_options
[option_idx
].short_option
;
155 switch (short_option
) {
157 m_end_addr
= OptionArgParser::ToRawAddress(
158 execution_context
, option_value
, LLDB_INVALID_ADDRESS
, &status
);
161 llvm_unreachable("Unimplemented option");
167 void OptionParsingStarting(ExecutionContext
*execution_context
) override
{
168 m_end_addr
= LLDB_INVALID_ADDRESS
;
171 lldb::addr_t m_end_addr
= LLDB_INVALID_ADDRESS
;
174 CommandObjectMemoryTagWrite(CommandInterpreter
&interpreter
)
175 : CommandObjectParsed(interpreter
, "tag",
176 "Write memory tags starting from the granule that "
177 "contains the given address.",
179 eCommandRequiresTarget
| eCommandRequiresProcess
|
180 eCommandProcessMustBePaused
) {
182 m_arguments
.push_back(
183 CommandArgumentEntry
{CommandArgumentData(eArgTypeAddressOrExpression
)});
184 // One or more tag values
185 m_arguments
.push_back(CommandArgumentEntry
{
186 CommandArgumentData(eArgTypeValue
, eArgRepeatPlus
)});
188 m_option_group
.Append(&m_tag_write_options
);
189 m_option_group
.Finalize();
192 ~CommandObjectMemoryTagWrite() override
= default;
194 Options
*GetOptions() override
{ return &m_option_group
; }
197 void DoExecute(Args
&command
, CommandReturnObject
&result
) override
{
198 if (command
.GetArgumentCount() < 2) {
199 result
.AppendError("wrong number of arguments; expected "
200 "<address-expression> <tag> [<tag> [...]]");
205 addr_t start_addr
= OptionArgParser::ToRawAddress(
206 &m_exe_ctx
, command
[0].ref(), LLDB_INVALID_ADDRESS
, &error
);
207 if (start_addr
== LLDB_INVALID_ADDRESS
) {
208 result
.AppendErrorWithFormatv("Invalid address expression, {0}",
213 command
.Shift(); // shift off start address
215 std::vector
<lldb::addr_t
> tags
;
216 for (auto &entry
: command
) {
217 lldb::addr_t tag_value
;
218 // getAsInteger returns true on failure
219 if (entry
.ref().getAsInteger(0, tag_value
)) {
220 result
.AppendErrorWithFormat(
221 "'%s' is not a valid unsigned decimal string value.\n",
225 tags
.push_back(tag_value
);
228 Process
*process
= m_exe_ctx
.GetProcessPtr();
229 llvm::Expected
<const MemoryTagManager
*> tag_manager_or_err
=
230 process
->GetMemoryTagManager();
232 if (!tag_manager_or_err
) {
233 result
.SetError(Status::FromError(tag_manager_or_err
.takeError()));
237 const MemoryTagManager
*tag_manager
= *tag_manager_or_err
;
239 MemoryRegionInfos memory_regions
;
240 // If this fails the list of regions is cleared, so we don't need to read
241 // the return status here.
242 process
->GetMemoryRegions(memory_regions
);
244 // The tag manager only removes tag bits. These addresses may include other
245 // non-address bits that must also be ignored.
246 ABISP abi
= process
->GetABI();
248 start_addr
= abi
->FixDataAddress(start_addr
);
250 // We have to assume start_addr is not granule aligned.
251 // So if we simply made a range:
252 // (start_addr, start_addr + (N * granule_size))
253 // We would end up with a range that isn't N granules but N+1
254 // granules. To avoid this we'll align the start first using the method that
255 // doesn't check memory attributes. (if the final range is untagged we'll
256 // handle that error later)
257 lldb::addr_t aligned_start_addr
=
258 tag_manager
->ExpandToGranule(MemoryTagManager::TagRange(start_addr
, 1))
261 lldb::addr_t end_addr
= 0;
262 // When you have an end address you want to align the range like tag read
263 // does. Meaning, align the start down (which we've done) and align the end
265 if (m_tag_write_options
.m_end_addr
!= LLDB_INVALID_ADDRESS
)
266 end_addr
= m_tag_write_options
.m_end_addr
;
268 // Without an end address assume number of tags matches number of granules
271 aligned_start_addr
+ (tags
.size() * tag_manager
->GetGranuleSize());
273 // Remove non-address bits that aren't memory tags
275 end_addr
= abi
->FixDataAddress(end_addr
);
277 // Now we've aligned the start address so if we ask for another range
278 // using the number of tags N, we'll get back a range that is also N
280 llvm::Expected
<MemoryTagManager::TagRange
> tagged_range
=
281 tag_manager
->MakeTaggedRange(aligned_start_addr
, end_addr
,
285 result
.SetError(Status::FromError(tagged_range
.takeError()));
289 Status status
= process
->WriteMemoryTags(tagged_range
->GetRangeBase(),
290 tagged_range
->GetByteSize(), tags
);
293 result
.SetError(std::move(status
));
297 result
.SetStatus(eReturnStatusSuccessFinishResult
);
300 OptionGroupOptions m_option_group
;
301 OptionGroupTagWrite m_tag_write_options
;
304 CommandObjectMemoryTag::CommandObjectMemoryTag(CommandInterpreter
&interpreter
)
305 : CommandObjectMultiword(
306 interpreter
, "tag", "Commands for manipulating memory tags",
307 "memory tag <sub-command> [<sub-command-options>]") {
308 CommandObjectSP
read_command_object(
309 new CommandObjectMemoryTagRead(interpreter
));
310 read_command_object
->SetCommandName("memory tag read");
311 LoadSubCommand("read", read_command_object
);
313 CommandObjectSP
write_command_object(
314 new CommandObjectMemoryTagWrite(interpreter
));
315 write_command_object
->SetCommandName("memory tag write");
316 LoadSubCommand("write", write_command_object
);
319 CommandObjectMemoryTag::~CommandObjectMemoryTag() = default;