aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Commands/CommandObjectMemoryTag.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Commands/CommandObjectMemoryTag.cpp')
-rw-r--r--lldb/source/Commands/CommandObjectMemoryTag.cpp182
1 files changed, 177 insertions, 5 deletions
diff --git a/lldb/source/Commands/CommandObjectMemoryTag.cpp b/lldb/source/Commands/CommandObjectMemoryTag.cpp
index 1dfb32a92f3b..840f81719d7d 100644
--- a/lldb/source/Commands/CommandObjectMemoryTag.cpp
+++ b/lldb/source/Commands/CommandObjectMemoryTag.cpp
@@ -7,8 +7,11 @@
//===----------------------------------------------------------------------===//
#include "CommandObjectMemoryTag.h"
+#include "lldb/Host/OptionParser.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Interpreter/OptionArgParser.h"
+#include "lldb/Interpreter/OptionGroupFormat.h"
+#include "lldb/Interpreter/OptionValueString.h"
#include "lldb/Target/Process.h"
using namespace lldb;
@@ -21,7 +24,8 @@ class CommandObjectMemoryTagRead : public CommandObjectParsed {
public:
CommandObjectMemoryTagRead(CommandInterpreter &interpreter)
: CommandObjectParsed(interpreter, "tag",
- "Read memory tags for the given range of memory.",
+ "Read memory tags for the given range of memory."
+ " Mismatched tags will be marked.",
nullptr,
eCommandRequiresTarget | eCommandRequiresProcess |
eCommandProcessMustBePaused) {
@@ -97,16 +101,17 @@ protected:
return false;
}
- result.AppendMessageWithFormatv("Logical tag: {0:x}",
- tag_manager->GetLogicalTag(start_addr));
+ lldb::addr_t logical_tag = tag_manager->GetLogicalTag(start_addr);
+ result.AppendMessageWithFormatv("Logical tag: {0:x}", logical_tag);
result.AppendMessage("Allocation tags:");
addr_t addr = tagged_range->GetRangeBase();
for (auto tag : *tags) {
addr_t next_addr = addr + tag_manager->GetGranuleSize();
// Showing tagged adresses here until we have non address bit handling
- result.AppendMessageWithFormatv("[{0:x}, {1:x}): {2:x}", addr, next_addr,
- tag);
+ result.AppendMessageWithFormatv("[{0:x}, {1:x}): {2:x}{3}", addr,
+ next_addr, tag,
+ logical_tag == tag ? "" : " (mismatch)");
addr = next_addr;
}
@@ -115,6 +120,168 @@ protected:
}
};
+#define LLDB_OPTIONS_memory_tag_write
+#include "CommandOptions.inc"
+
+class CommandObjectMemoryTagWrite : public CommandObjectParsed {
+public:
+ class OptionGroupTagWrite : public OptionGroup {
+ public:
+ OptionGroupTagWrite() : OptionGroup(), m_end_addr(LLDB_INVALID_ADDRESS) {}
+
+ ~OptionGroupTagWrite() override = default;
+
+ llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
+ return llvm::makeArrayRef(g_memory_tag_write_options);
+ }
+
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
+ ExecutionContext *execution_context) override {
+ Status status;
+ const int short_option =
+ g_memory_tag_write_options[option_idx].short_option;
+
+ switch (short_option) {
+ case 'e':
+ m_end_addr = OptionArgParser::ToAddress(execution_context, option_value,
+ LLDB_INVALID_ADDRESS, &status);
+ break;
+ default:
+ llvm_unreachable("Unimplemented option");
+ }
+
+ return status;
+ }
+
+ void OptionParsingStarting(ExecutionContext *execution_context) override {
+ m_end_addr = LLDB_INVALID_ADDRESS;
+ }
+
+ lldb::addr_t m_end_addr;
+ };
+
+ CommandObjectMemoryTagWrite(CommandInterpreter &interpreter)
+ : CommandObjectParsed(interpreter, "tag",
+ "Write memory tags starting from the granule that "
+ "contains the given address.",
+ nullptr,
+ eCommandRequiresTarget | eCommandRequiresProcess |
+ eCommandProcessMustBePaused),
+ m_option_group(), m_tag_write_options() {
+ // Address
+ m_arguments.push_back(
+ CommandArgumentEntry{CommandArgumentData(eArgTypeAddressOrExpression)});
+ // One or more tag values
+ m_arguments.push_back(CommandArgumentEntry{
+ CommandArgumentData(eArgTypeValue, eArgRepeatPlus)});
+
+ m_option_group.Append(&m_tag_write_options);
+ m_option_group.Finalize();
+ }
+
+ ~CommandObjectMemoryTagWrite() override = default;
+
+ Options *GetOptions() override { return &m_option_group; }
+
+protected:
+ bool DoExecute(Args &command, CommandReturnObject &result) override {
+ if (command.GetArgumentCount() < 2) {
+ result.AppendError("wrong number of arguments; expected "
+ "<address-expression> <tag> [<tag> [...]]");
+ return false;
+ }
+
+ Status error;
+ addr_t start_addr = OptionArgParser::ToAddress(
+ &m_exe_ctx, command[0].ref(), LLDB_INVALID_ADDRESS, &error);
+ if (start_addr == LLDB_INVALID_ADDRESS) {
+ result.AppendErrorWithFormatv("Invalid address expression, {0}",
+ error.AsCString());
+ return false;
+ }
+
+ command.Shift(); // shift off start address
+
+ std::vector<lldb::addr_t> tags;
+ for (auto &entry : command) {
+ lldb::addr_t tag_value;
+ // getAsInteger returns true on failure
+ if (entry.ref().getAsInteger(0, tag_value)) {
+ result.AppendErrorWithFormat(
+ "'%s' is not a valid unsigned decimal string value.\n",
+ entry.c_str());
+ return false;
+ }
+ tags.push_back(tag_value);
+ }
+
+ Process *process = m_exe_ctx.GetProcessPtr();
+ llvm::Expected<const MemoryTagManager *> tag_manager_or_err =
+ process->GetMemoryTagManager();
+
+ if (!tag_manager_or_err) {
+ result.SetError(Status(tag_manager_or_err.takeError()));
+ return false;
+ }
+
+ const MemoryTagManager *tag_manager = *tag_manager_or_err;
+
+ MemoryRegionInfos memory_regions;
+ // If this fails the list of regions is cleared, so we don't need to read
+ // the return status here.
+ process->GetMemoryRegions(memory_regions);
+
+ // We have to assume start_addr is not granule aligned.
+ // So if we simply made a range:
+ // (start_addr, start_addr + (N * granule_size))
+ // We would end up with a range that isn't N granules but N+1
+ // granules. To avoid this we'll align the start first using the method that
+ // doesn't check memory attributes. (if the final range is untagged we'll
+ // handle that error later)
+ lldb::addr_t aligned_start_addr =
+ tag_manager->ExpandToGranule(MemoryTagManager::TagRange(start_addr, 1))
+ .GetRangeBase();
+
+ lldb::addr_t end_addr = 0;
+ // When you have an end address you want to align the range like tag read
+ // does. Meaning, align the start down (which we've done) and align the end
+ // up.
+ if (m_tag_write_options.m_end_addr != LLDB_INVALID_ADDRESS)
+ end_addr = m_tag_write_options.m_end_addr;
+ else
+ // Without an end address assume number of tags matches number of granules
+ // to write to
+ end_addr =
+ aligned_start_addr + (tags.size() * tag_manager->GetGranuleSize());
+
+ // Now we've aligned the start address so if we ask for another range
+ // using the number of tags N, we'll get back a range that is also N
+ // granules in size.
+ llvm::Expected<MemoryTagManager::TagRange> tagged_range =
+ tag_manager->MakeTaggedRange(aligned_start_addr, end_addr,
+ memory_regions);
+
+ if (!tagged_range) {
+ result.SetError(Status(tagged_range.takeError()));
+ return false;
+ }
+
+ Status status = process->WriteMemoryTags(tagged_range->GetRangeBase(),
+ tagged_range->GetByteSize(), tags);
+
+ if (status.Fail()) {
+ result.SetError(status);
+ return false;
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return true;
+ }
+
+ OptionGroupOptions m_option_group;
+ OptionGroupTagWrite m_tag_write_options;
+};
+
CommandObjectMemoryTag::CommandObjectMemoryTag(CommandInterpreter &interpreter)
: CommandObjectMultiword(
interpreter, "tag", "Commands for manipulating memory tags",
@@ -123,6 +290,11 @@ CommandObjectMemoryTag::CommandObjectMemoryTag(CommandInterpreter &interpreter)
new CommandObjectMemoryTagRead(interpreter));
read_command_object->SetCommandName("memory tag read");
LoadSubCommand("read", read_command_object);
+
+ CommandObjectSP write_command_object(
+ new CommandObjectMemoryTagWrite(interpreter));
+ write_command_object->SetCommandName("memory tag write");
+ LoadSubCommand("write", write_command_object);
}
CommandObjectMemoryTag::~CommandObjectMemoryTag() = default;