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 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 53 Status error; 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}", 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(), 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; 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; 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; 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; 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 } 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() = default; 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': 157 m_end_addr = OptionArgParser::ToRawAddress( 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 { 168 m_end_addr = LLDB_INVALID_ADDRESS; 169 } 170 171 lldb::addr_t m_end_addr = LLDB_INVALID_ADDRESS; 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 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 204 Status error; 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}", 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)) { 220 result.AppendErrorWithFormat( 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(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. 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; 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; 295 } 296 297 result.SetStatus(eReturnStatusSuccessFinishResult); 298 } 299 300 OptionGroupOptions m_option_group; 301 OptionGroupTagWrite m_tag_write_options; 302 }; 303 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); 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 319 CommandObjectMemoryTag::~CommandObjectMemoryTag() = default; 320