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 9 #include "CommandObjectMemoryTag.h" 10 #include "lldb/Host/OptionParser.h" 11 #include "lldb/Interpreter/CommandReturnObject.h" 12 #include "lldb/Interpreter/OptionArgParser.h" 13 #include "lldb/Interpreter/OptionGroupFormat.h" 14 #include "lldb/Interpreter/OptionValueString.h" 15 #include "lldb/Target/ABI.h" 16 #include "lldb/Target/Process.h" 17 18 using namespace lldb; 19 using namespace lldb_private; 20 21 #define LLDB_OPTIONS_memory_tag_read 22 #include "CommandOptions.inc" 23 24 class CommandObjectMemoryTagRead : public CommandObjectParsed { 25 public: 26 CommandObjectMemoryTagRead(CommandInterpreter &interpreter) 27 : CommandObjectParsed(interpreter, "tag", 28 "Read memory tags for the given range of memory." 29 " Mismatched tags will be marked.", 30 nullptr, 31 eCommandRequiresTarget | eCommandRequiresProcess | 32 eCommandProcessMustBePaused) { 33 // Address 34 m_arguments.push_back( 35 CommandArgumentEntry{CommandArgumentData(eArgTypeAddressOrExpression)}); 36 // Optional end address 37 m_arguments.push_back(CommandArgumentEntry{ 38 CommandArgumentData(eArgTypeAddressOrExpression, eArgRepeatOptional)}); 39 } 40 41 ~CommandObjectMemoryTagRead() override = default; 42 43 protected: 44 bool DoExecute(Args &command, CommandReturnObject &result) override { 45 if ((command.GetArgumentCount() < 1) || (command.GetArgumentCount() > 2)) { 46 result.AppendError( 47 "wrong number of arguments; expected at least <address-expression>, " 48 "at most <address-expression> <end-address-expression>"); 49 return false; 50 } 51 52 Status error; 53 addr_t start_addr = OptionArgParser::ToAddress( 54 &m_exe_ctx, command[0].ref(), LLDB_INVALID_ADDRESS, &error); 55 if (start_addr == LLDB_INVALID_ADDRESS) { 56 result.AppendErrorWithFormatv("Invalid address expression, {0}", 57 error.AsCString()); 58 return false; 59 } 60 61 // Default 1 byte beyond start, rounds up to at most 1 granule later 62 addr_t end_addr = start_addr + 1; 63 64 if (command.GetArgumentCount() > 1) { 65 end_addr = OptionArgParser::ToAddress(&m_exe_ctx, command[1].ref(), 66 LLDB_INVALID_ADDRESS, &error); 67 if (end_addr == LLDB_INVALID_ADDRESS) { 68 result.AppendErrorWithFormatv("Invalid end address expression, {0}", 69 error.AsCString()); 70 return false; 71 } 72 } 73 74 Process *process = m_exe_ctx.GetProcessPtr(); 75 llvm::Expected<const MemoryTagManager *> tag_manager_or_err = 76 process->GetMemoryTagManager(); 77 78 if (!tag_manager_or_err) { 79 result.SetError(Status(tag_manager_or_err.takeError())); 80 return false; 81 } 82 83 const MemoryTagManager *tag_manager = *tag_manager_or_err; 84 85 MemoryRegionInfos memory_regions; 86 // If this fails the list of regions is cleared, so we don't need to read 87 // the return status here. 88 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 100 llvm::Expected<MemoryTagManager::TagRange> tagged_range = 101 tag_manager->MakeTaggedRange(start_addr, end_addr, memory_regions); 102 103 if (!tagged_range) { 104 result.SetError(Status(tagged_range.takeError())); 105 return false; 106 } 107 108 llvm::Expected<std::vector<lldb::addr_t>> tags = process->ReadMemoryTags( 109 tagged_range->GetRangeBase(), tagged_range->GetByteSize()); 110 111 if (!tags) { 112 result.SetError(Status(tags.takeError())); 113 return false; 114 } 115 116 result.AppendMessageWithFormatv("Logical tag: {0:x}", logical_tag); 117 result.AppendMessage("Allocation tags:"); 118 119 addr_t addr = tagged_range->GetRangeBase(); 120 for (auto tag : *tags) { 121 addr_t next_addr = addr + tag_manager->GetGranuleSize(); 122 // Showing tagged adresses here until we have non address bit handling 123 result.AppendMessageWithFormatv("[{0:x}, {1:x}): {2:x}{3}", addr, 124 next_addr, tag, 125 logical_tag == tag ? "" : " (mismatch)"); 126 addr = next_addr; 127 } 128 129 result.SetStatus(eReturnStatusSuccessFinishResult); 130 return true; 131 } 132 }; 133 134 #define LLDB_OPTIONS_memory_tag_write 135 #include "CommandOptions.inc" 136 137 class CommandObjectMemoryTagWrite : public CommandObjectParsed { 138 public: 139 class OptionGroupTagWrite : public OptionGroup { 140 public: 141 OptionGroupTagWrite() : m_end_addr(LLDB_INVALID_ADDRESS) {} 142 143 ~OptionGroupTagWrite() override = default; 144 145 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 146 return llvm::makeArrayRef(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': 157 m_end_addr = OptionArgParser::ToAddress(execution_context, option_value, 158 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 { 168 m_end_addr = LLDB_INVALID_ADDRESS; 169 } 170 171 lldb::addr_t m_end_addr; 172 }; 173 174 CommandObjectMemoryTagWrite(CommandInterpreter &interpreter) 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( 183 CommandArgumentEntry{CommandArgumentData(eArgTypeAddressOrExpression)}); 184 // One or more tag values 185 m_arguments.push_back(CommandArgumentEntry{ 186 CommandArgumentData(eArgTypeValue, eArgRepeatPlus)}); 187 188 m_option_group.Append(&m_tag_write_options); 189 m_option_group.Finalize(); 190 } 191 192 ~CommandObjectMemoryTagWrite() override = default; 193 194 Options *GetOptions() override { return &m_option_group; } 195 196 protected: 197 bool 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 false; 202 } 203 204 Status error; 205 addr_t start_addr = OptionArgParser::ToAddress( 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 false; 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)) { 220 result.AppendErrorWithFormat( 221 "'%s' is not a valid unsigned decimal string value.\n", 222 entry.c_str()); 223 return false; 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(tag_manager_or_err.takeError())); 234 return false; 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. 265 if (m_tag_write_options.m_end_addr != LLDB_INVALID_ADDRESS) 266 end_addr = m_tag_write_options.m_end_addr; 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(tagged_range.takeError())); 286 return false; 287 } 288 289 Status status = process->WriteMemoryTags(tagged_range->GetRangeBase(), 290 tagged_range->GetByteSize(), tags); 291 292 if (status.Fail()) { 293 result.SetError(status); 294 return false; 295 } 296 297 result.SetStatus(eReturnStatusSuccessFinishResult); 298 return true; 299 } 300 301 OptionGroupOptions m_option_group; 302 OptionGroupTagWrite m_tag_write_options; 303 }; 304 305 CommandObjectMemoryTag::CommandObjectMemoryTag(CommandInterpreter &interpreter) 306 : CommandObjectMultiword( 307 interpreter, "tag", "Commands for manipulating memory tags", 308 "memory tag <sub-command> [<sub-command-options>]") { 309 CommandObjectSP read_command_object( 310 new CommandObjectMemoryTagRead(interpreter)); 311 read_command_object->SetCommandName("memory tag read"); 312 LoadSubCommand("read", read_command_object); 313 314 CommandObjectSP write_command_object( 315 new CommandObjectMemoryTagWrite(interpreter)); 316 write_command_object->SetCommandName("memory tag write"); 317 LoadSubCommand("write", write_command_object); 318 } 319 320 CommandObjectMemoryTag::~CommandObjectMemoryTag() = default; 321