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/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" 18 19 using namespace lldb; 20 using namespace lldb_private; 21 22 #define LLDB_OPTIONS_memory_tag_read 23 #include "CommandOptions.inc" 24 25 class CommandObjectMemoryTagRead : public CommandObjectParsed { 26 public: 27 CommandObjectMemoryTagRead(CommandInterpreter &interpreter) 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( 36 CommandArgumentEntry{CommandArgumentData(eArgTypeAddressOrExpression)}); 37 // Optional end address 38 m_arguments.push_back(CommandArgumentEntry{ 39 CommandArgumentData(eArgTypeAddressOrExpression, eArgRepeatOptional)}); 40 } 41 42 ~CommandObjectMemoryTagRead() override = default; 43 44 protected: 45 bool 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 false; 51 } 52 53 Status error; 54 addr_t start_addr = OptionArgParser::ToAddress( 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 false; 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::ToAddress(&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}", 70 error.AsCString()); 71 return false; 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(tag_manager_or_err.takeError())); 81 return false; 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(tagged_range.takeError())); 106 return false; 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(tags.takeError())); 114 return false; 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 130 result.SetStatus(eReturnStatusSuccessFinishResult); 131 return true; 132 } 133 }; 134 135 #define LLDB_OPTIONS_memory_tag_write 136 #include "CommandOptions.inc" 137 138 class CommandObjectMemoryTagWrite : public CommandObjectParsed { 139 public: 140 class OptionGroupTagWrite : public OptionGroup { 141 public: 142 OptionGroupTagWrite() = default; 143 144 ~OptionGroupTagWrite() override = default; 145 146 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 147 return llvm::ArrayRef(g_memory_tag_write_options); 148 } 149 150 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, 151 ExecutionContext *execution_context) override { 152 Status status; 153 const int short_option = 154 g_memory_tag_write_options[option_idx].short_option; 155 156 switch (short_option) { 157 case 'e': 158 m_end_addr = OptionArgParser::ToAddress(execution_context, option_value, 159 LLDB_INVALID_ADDRESS, &status); 160 break; 161 default: 162 llvm_unreachable("Unimplemented option"); 163 } 164 165 return status; 166 } 167 168 void OptionParsingStarting(ExecutionContext *execution_context) override { 169 m_end_addr = LLDB_INVALID_ADDRESS; 170 } 171 172 lldb::addr_t m_end_addr = LLDB_INVALID_ADDRESS; 173 }; 174 175 CommandObjectMemoryTagWrite(CommandInterpreter &interpreter) 176 : CommandObjectParsed(interpreter, "tag", 177 "Write memory tags starting from the granule that " 178 "contains the given address.", 179 nullptr, 180 eCommandRequiresTarget | eCommandRequiresProcess | 181 eCommandProcessMustBePaused) { 182 // Address 183 m_arguments.push_back( 184 CommandArgumentEntry{CommandArgumentData(eArgTypeAddressOrExpression)}); 185 // One or more tag values 186 m_arguments.push_back(CommandArgumentEntry{ 187 CommandArgumentData(eArgTypeValue, eArgRepeatPlus)}); 188 189 m_option_group.Append(&m_tag_write_options); 190 m_option_group.Finalize(); 191 } 192 193 ~CommandObjectMemoryTagWrite() override = default; 194 195 Options *GetOptions() override { return &m_option_group; } 196 197 protected: 198 bool DoExecute(Args &command, CommandReturnObject &result) override { 199 if (command.GetArgumentCount() < 2) { 200 result.AppendError("wrong number of arguments; expected " 201 "<address-expression> <tag> [<tag> [...]]"); 202 return false; 203 } 204 205 Status error; 206 addr_t start_addr = OptionArgParser::ToAddress( 207 &m_exe_ctx, command[0].ref(), LLDB_INVALID_ADDRESS, &error); 208 if (start_addr == LLDB_INVALID_ADDRESS) { 209 result.AppendErrorWithFormatv("Invalid address expression, {0}", 210 error.AsCString()); 211 return false; 212 } 213 214 command.Shift(); // shift off start address 215 216 std::vector<lldb::addr_t> tags; 217 for (auto &entry : command) { 218 lldb::addr_t tag_value; 219 // getAsInteger returns true on failure 220 if (entry.ref().getAsInteger(0, tag_value)) { 221 result.AppendErrorWithFormat( 222 "'%s' is not a valid unsigned decimal string value.\n", 223 entry.c_str()); 224 return false; 225 } 226 tags.push_back(tag_value); 227 } 228 229 Process *process = m_exe_ctx.GetProcessPtr(); 230 llvm::Expected<const MemoryTagManager *> tag_manager_or_err = 231 process->GetMemoryTagManager(); 232 233 if (!tag_manager_or_err) { 234 result.SetError(Status(tag_manager_or_err.takeError())); 235 return false; 236 } 237 238 const MemoryTagManager *tag_manager = *tag_manager_or_err; 239 240 MemoryRegionInfos memory_regions; 241 // If this fails the list of regions is cleared, so we don't need to read 242 // the return status here. 243 process->GetMemoryRegions(memory_regions); 244 245 // The tag manager only removes tag bits. These addresses may include other 246 // non-address bits that must also be ignored. 247 ABISP abi = process->GetABI(); 248 if (abi) 249 start_addr = abi->FixDataAddress(start_addr); 250 251 // We have to assume start_addr is not granule aligned. 252 // So if we simply made a range: 253 // (start_addr, start_addr + (N * granule_size)) 254 // We would end up with a range that isn't N granules but N+1 255 // granules. To avoid this we'll align the start first using the method that 256 // doesn't check memory attributes. (if the final range is untagged we'll 257 // handle that error later) 258 lldb::addr_t aligned_start_addr = 259 tag_manager->ExpandToGranule(MemoryTagManager::TagRange(start_addr, 1)) 260 .GetRangeBase(); 261 262 lldb::addr_t end_addr = 0; 263 // When you have an end address you want to align the range like tag read 264 // does. Meaning, align the start down (which we've done) and align the end 265 // up. 266 if (m_tag_write_options.m_end_addr != LLDB_INVALID_ADDRESS) 267 end_addr = m_tag_write_options.m_end_addr; 268 else 269 // Without an end address assume number of tags matches number of granules 270 // to write to 271 end_addr = 272 aligned_start_addr + (tags.size() * tag_manager->GetGranuleSize()); 273 274 // Remove non-address bits that aren't memory tags 275 if (abi) 276 end_addr = abi->FixDataAddress(end_addr); 277 278 // Now we've aligned the start address so if we ask for another range 279 // using the number of tags N, we'll get back a range that is also N 280 // granules in size. 281 llvm::Expected<MemoryTagManager::TagRange> tagged_range = 282 tag_manager->MakeTaggedRange(aligned_start_addr, end_addr, 283 memory_regions); 284 285 if (!tagged_range) { 286 result.SetError(Status(tagged_range.takeError())); 287 return false; 288 } 289 290 Status status = process->WriteMemoryTags(tagged_range->GetRangeBase(), 291 tagged_range->GetByteSize(), tags); 292 293 if (status.Fail()) { 294 result.SetError(status); 295 return false; 296 } 297 298 result.SetStatus(eReturnStatusSuccessFinishResult); 299 return true; 300 } 301 302 OptionGroupOptions m_option_group; 303 OptionGroupTagWrite m_tag_write_options; 304 }; 305 306 CommandObjectMemoryTag::CommandObjectMemoryTag(CommandInterpreter &interpreter) 307 : CommandObjectMultiword( 308 interpreter, "tag", "Commands for manipulating memory tags", 309 "memory tag <sub-command> [<sub-command-options>]") { 310 CommandObjectSP read_command_object( 311 new CommandObjectMemoryTagRead(interpreter)); 312 read_command_object->SetCommandName("memory tag read"); 313 LoadSubCommand("read", read_command_object); 314 315 CommandObjectSP write_command_object( 316 new CommandObjectMemoryTagWrite(interpreter)); 317 write_command_object->SetCommandName("memory tag write"); 318 LoadSubCommand("write", write_command_object); 319 } 320 321 CommandObjectMemoryTag::~CommandObjectMemoryTag() = default; 322