LLDB mainline
CommandObjectMemoryTag.cpp
Go to the documentation of this file.
1//===-- CommandObjectMemoryTag.cpp ----------------------------------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
16#include "lldb/Target/ABI.h"
17#include "lldb/Target/Process.h"
18
19using namespace lldb;
20using namespace lldb_private;
21
22#define LLDB_OPTIONS_memory_tag_read
23#include "CommandOptions.inc"
24
26public:
28 : CommandObjectParsed(interpreter, "tag",
29 "Read memory tags for the given range of memory."
30 " Mismatched tags will be marked.",
31 nullptr,
32 eCommandRequiresTarget | eCommandRequiresProcess |
33 eCommandProcessMustBePaused) {
34 // Address
35 m_arguments.push_back(
37 // Optional end address
40 }
41
42 ~CommandObjectMemoryTagRead() override = default;
43
44protected:
45 void DoExecute(Args &command, CommandReturnObject &result) override {
46 if ((command.GetArgumentCount() < 1) || (command.GetArgumentCount() > 2)) {
47 result.AppendError(
48 "wrong number of arguments; expected at least <address-expression>, "
49 "at most <address-expression> <end-address-expression>");
50 return;
51 }
52
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}",
58 error.AsCString());
59 return;
60 }
61
62 // Default 1 byte beyond start, rounds up to at most 1 granule later
63 addr_t end_addr = start_addr + 1;
64
65 if (command.GetArgumentCount() > 1) {
66 end_addr = OptionArgParser::ToRawAddress(&m_exe_ctx, command[1].ref(),
68 if (end_addr == LLDB_INVALID_ADDRESS) {
69 result.AppendErrorWithFormatv("Invalid end address expression, {0}",
70 error.AsCString());
71 return;
72 }
73 }
74
75 Process *process = m_exe_ctx.GetProcessPtr();
76 llvm::Expected<const MemoryTagManager *> tag_manager_or_err =
77 process->GetMemoryTagManager();
78
79 if (!tag_manager_or_err) {
80 result.SetError(Status::FromError(tag_manager_or_err.takeError()));
81 return;
82 }
83
84 const MemoryTagManager *tag_manager = *tag_manager_or_err;
85
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);
90
91 lldb::addr_t logical_tag = tag_manager->GetLogicalTag(start_addr);
92
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();
96 if (abi) {
97 start_addr = abi->FixDataAddress(start_addr);
98 end_addr = abi->FixDataAddress(end_addr);
99 }
100
101 llvm::Expected<MemoryTagManager::TagRange> tagged_range =
102 tag_manager->MakeTaggedRange(start_addr, end_addr, memory_regions);
103
104 if (!tagged_range) {
105 result.SetError(Status::FromError(tagged_range.takeError()));
106 return;
107 }
108
109 llvm::Expected<std::vector<lldb::addr_t>> tags = process->ReadMemoryTags(
110 tagged_range->GetRangeBase(), tagged_range->GetByteSize());
111
112 if (!tags) {
113 result.SetError(Status::FromError(tags.takeError()));
114 return;
115 }
116
117 result.AppendMessageWithFormatv("Logical tag: {0:x}", logical_tag);
118 result.AppendMessage("Allocation tags:");
119
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,
125 next_addr, tag,
126 logical_tag == tag ? "" : " (mismatch)");
127 addr = next_addr;
128 }
129
131 }
132};
133
134#define LLDB_OPTIONS_memory_tag_write
135#include "CommandOptions.inc"
136
138public:
140 public:
142
143 ~OptionGroupTagWrite() override = default;
144
145 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
146 return llvm::ArrayRef(g_memory_tag_write_options);
147 }
148
149 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
150 ExecutionContext *execution_context) override {
151 Status status;
152 const int short_option =
153 g_memory_tag_write_options[option_idx].short_option;
154
155 switch (short_option) {
156 case 'e':
158 execution_context, option_value, LLDB_INVALID_ADDRESS, &status);
159 break;
160 default:
161 llvm_unreachable("Unimplemented option");
162 }
163
164 return status;
165 }
166
167 void OptionParsingStarting(ExecutionContext *execution_context) override {
169 }
170
172 };
173
175 : CommandObjectParsed(interpreter, "tag",
176 "Write memory tags starting from the granule that "
177 "contains the given address.",
178 nullptr,
179 eCommandRequiresTarget | eCommandRequiresProcess |
180 eCommandProcessMustBePaused) {
181 // Address
182 m_arguments.push_back(
184 // One or more tag values
187
190 }
191
192 ~CommandObjectMemoryTagWrite() override = default;
193
194 Options *GetOptions() override { return &m_option_group; }
195
196protected:
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> [...]]");
201 return;
202 }
203
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}",
209 error.AsCString());
210 return;
211 }
212
213 command.Shift(); // shift off start address
214
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)) {
221 "'%s' is not a valid unsigned decimal string value.\n",
222 entry.c_str());
223 return;
224 }
225 tags.push_back(tag_value);
226 }
227
228 Process *process = m_exe_ctx.GetProcessPtr();
229 llvm::Expected<const MemoryTagManager *> tag_manager_or_err =
230 process->GetMemoryTagManager();
231
232 if (!tag_manager_or_err) {
233 result.SetError(Status::FromError(tag_manager_or_err.takeError()));
234 return;
235 }
236
237 const MemoryTagManager *tag_manager = *tag_manager_or_err;
238
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);
243
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();
247 if (abi)
248 start_addr = abi->FixDataAddress(start_addr);
249
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))
259 .GetRangeBase();
260
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
264 // up.
267 else
268 // Without an end address assume number of tags matches number of granules
269 // to write to
270 end_addr =
271 aligned_start_addr + (tags.size() * tag_manager->GetGranuleSize());
272
273 // Remove non-address bits that aren't memory tags
274 if (abi)
275 end_addr = abi->FixDataAddress(end_addr);
276
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
279 // granules in size.
280 llvm::Expected<MemoryTagManager::TagRange> tagged_range =
281 tag_manager->MakeTaggedRange(aligned_start_addr, end_addr,
282 memory_regions);
283
284 if (!tagged_range) {
285 result.SetError(Status::FromError(tagged_range.takeError()));
286 return;
287 }
288
289 Status status = process->WriteMemoryTags(tagged_range->GetRangeBase(),
290 tagged_range->GetByteSize(), tags);
291
292 if (status.Fail()) {
293 result.SetError(std::move(status));
294 return;
295 }
296
298 }
299
302};
303
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);
312
313 CommandObjectSP write_command_object(
314 new CommandObjectMemoryTagWrite(interpreter));
315 write_command_object->SetCommandName("memory tag write");
316 LoadSubCommand("write", write_command_object);
317}
318
static llvm::raw_ostream & error(Stream &strm)
void DoExecute(Args &command, CommandReturnObject &result) override
~CommandObjectMemoryTagRead() override=default
CommandObjectMemoryTagRead(CommandInterpreter &interpreter)
llvm::ArrayRef< OptionDefinition > GetDefinitions() override
void OptionParsingStarting(ExecutionContext *execution_context) override
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, ExecutionContext *execution_context) override
~CommandObjectMemoryTagWrite() override=default
CommandObjectMemoryTagWrite(CommandInterpreter &interpreter)
void DoExecute(Args &command, CommandReturnObject &result) override
A command line argument class.
Definition: Args.h:33
void Shift()
Shifts the first argument C string value of the array off the argument array.
Definition: Args.cpp:295
size_t GetArgumentCount() const
Gets the number of arguments left in this command object.
Definition: Args.h:120
CommandObjectMemoryTag(CommandInterpreter &interpreter)
bool LoadSubCommand(llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_obj) override
std::vector< CommandArgumentData > CommandArgumentEntry
ExecutionContext m_exe_ctx
std::vector< CommandArgumentEntry > m_arguments
void AppendErrorWithFormatv(const char *format, Args &&... args)
void AppendMessage(llvm::StringRef in_string)
void void AppendError(llvm::StringRef in_string)
void SetStatus(lldb::ReturnStatus status)
void void AppendMessageWithFormatv(const char *format, Args &&... args)
void AppendErrorWithFormat(const char *format,...) __attribute__((format(printf
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
Process * GetProcessPtr() const
Returns a pointer to the process object.
virtual TagRange ExpandToGranule(TagRange range) const =0
virtual llvm::Expected< TagRange > MakeTaggedRange(lldb::addr_t addr, lldb::addr_t end_addr, const lldb_private::MemoryRegionInfos &memory_regions) const =0
virtual lldb::addr_t GetGranuleSize() const =0
virtual lldb::addr_t GetLogicalTag(lldb::addr_t addr) const =0
void Append(OptionGroup *group)
Append options from a OptionGroup class.
Definition: Options.cpp:788
A command line option parsing protocol class.
Definition: Options.h:58
A plug-in interface definition class for debugging a process.
Definition: Process.h:343
llvm::Expected< const MemoryTagManager * > GetMemoryTagManager()
If this architecture and process supports memory tagging, return a tag manager that can be used to ma...
Definition: Process.cpp:6425
virtual llvm::Expected< std::vector< lldb::addr_t > > ReadMemoryTags(lldb::addr_t addr, size_t len)
Read memory tags for the range addr to addr+len.
Definition: Process.cpp:6444
virtual Status GetMemoryRegions(lldb_private::MemoryRegionInfos &region_list)
Obtain all the mapped memory regions within this process.
Definition: Process.cpp:6200
Status WriteMemoryTags(lldb::addr_t addr, size_t len, const std::vector< lldb::addr_t > &tags)
Write memory tags for a range of memory.
Definition: Process.cpp:6460
const lldb::ABISP & GetABI()
Definition: Process.cpp:1504
An error handling class.
Definition: Status.h:115
bool Fail() const
Test for error condition.
Definition: Status.cpp:270
static Status FromError(llvm::Error error)
Avoid using this in new code. Migrate APIs to llvm::Expected instead.
Definition: Status.cpp:137
#define LLDB_INVALID_ADDRESS
Definition: lldb-defines.h:82
A class that represents a running process on the host machine.
Definition: SBAddress.h:15
std::shared_ptr< lldb_private::ABI > ABISP
Definition: lldb-forward.h:317
std::shared_ptr< lldb_private::CommandObject > CommandObjectSP
Definition: lldb-forward.h:333
@ eReturnStatusSuccessFinishResult
@ eArgTypeAddressOrExpression
uint64_t addr_t
Definition: lldb-types.h:80
Used to build individual command argument lists.
Definition: CommandObject.h:95
static lldb::addr_t ToRawAddress(const ExecutionContext *exe_ctx, llvm::StringRef s, lldb::addr_t fail_value, Status *error_ptr)
As for ToAddress but do not remove non-address bits from the result.
BaseType GetRangeBase() const
Definition: RangeMap.h:45