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 
10 #include "lldb/Host/OptionParser.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 
26 public:
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
38  m_arguments.push_back(CommandArgumentEntry{
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(),
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 
131  return true;
132  }
133 };
134 
135 #define LLDB_OPTIONS_memory_tag_write
136 #include "CommandOptions.inc"
137 
139 public:
141  public:
142  OptionGroupTagWrite() = default;
143 
144  ~OptionGroupTagWrite() override = default;
145 
146  llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
147  return llvm::makeArrayRef(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 
173  };
174 
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(
185  // One or more tag values
186  m_arguments.push_back(CommandArgumentEntry{
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 
299  return true;
300  }
301 
304 };
305 
306 CommandObjectMemoryTag::CommandObjectMemoryTag(CommandInterpreter &interpreter)
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 
CommandObjectMemoryTagWrite::m_option_group
OptionGroupOptions m_option_group
Definition: CommandObjectMemoryTag.cpp:302
lldb_private::eArgRepeatOptional
@ eArgRepeatOptional
Definition: lldb-private-enumerations.h:96
lldb_private::CommandObjectParsed
Definition: CommandObject.h:390
lldb_private::Range::GetRangeBase
BaseType GetRangeBase() const
Definition: RangeMap.h:46
lldb_private::ExecutionContext
Definition: ExecutionContext.h:292
OptionGroupFormat.h
lldb_private::CommandReturnObject::SetError
void SetError(const Status &error, const char *fallback_error_cstr=nullptr)
Definition: CommandReturnObject.cpp:107
CommandObjectMemoryTagWrite::DoExecute
bool DoExecute(Args &command, CommandReturnObject &result) override
Definition: CommandObjectMemoryTag.cpp:198
lldb_private::Args::Shift
void Shift()
Shifts the first argument C string value of the array off the argument array.
Definition: Args.cpp:286
lldb_private::Process
Definition: Process.h:338
lldb_private::OptionGroupOptions
Definition: Options.h:255
lldb_private::CommandObject::CommandArgumentData
Used to build individual command argument lists.
Definition: CommandObject.h:92
lldb_private::Process::GetMemoryRegions
virtual Status GetMemoryRegions(lldb_private::MemoryRegionInfos &region_list)
Obtain all the mapped memory regions within this process.
Definition: Process.cpp:5881
lldb_private::OptionGroup
Definition: Options.h:233
lldb::eArgTypeAddressOrExpression
@ eArgTypeAddressOrExpression
Definition: lldb-enumerations.h:518
OptionArgParser.h
lldb_private::MemoryTagManager::MakeTaggedRange
virtual llvm::Expected< TagRange > MakeTaggedRange(lldb::addr_t addr, lldb::addr_t end_addr, const lldb_private::MemoryRegionInfos &memory_regions) const =0
lldb::eArgTypeValue
@ eArgTypeValue
Definition: lldb-enumerations.h:594
lldb_private::Args
Definition: Args.h:33
lldb::addr_t
uint64_t addr_t
Definition: lldb-types.h:83
lldb_private::eArgRepeatPlus
@ eArgRepeatPlus
Definition: lldb-private-enumerations.h:97
CommandReturnObject.h
lldb_private::CommandReturnObject::AppendErrorWithFormatv
void AppendErrorWithFormatv(const char *format, Args &&... args)
Definition: CommandReturnObject.h:130
lldb_private::MemoryTagManager::GetLogicalTag
virtual lldb::addr_t GetLogicalTag(lldb::addr_t addr) const =0
ABI.h
Process.h
lldb_private::MemoryTagManager
Definition: MemoryTagManager.h:28
lldb_private::CommandObjectMultiword
Definition: CommandObjectMultiword.h:19
error
static llvm::raw_ostream & error(Stream &strm)
Definition: CommandReturnObject.cpp:17
lldb_private::Options
Definition: Options.h:57
lldb_private::CommandObjectMultiword::LoadSubCommand
bool LoadSubCommand(llvm::StringRef cmd_name, const lldb::CommandObjectSP &command_obj) override
Definition: CommandObjectMultiword.cpp:80
lldb_private::CommandReturnObject::SetStatus
void SetStatus(lldb::ReturnStatus status)
Definition: CommandReturnObject.cpp:127
lldb_private::Status::Fail
bool Fail() const
Test for error condition.
Definition: Status.cpp:181
CommandObjectMemoryTagWrite::OptionGroupTagWrite
Definition: CommandObjectMemoryTag.cpp:140
lldb_private::MemoryRegionInfos
Definition: MemoryRegionInfo.h:172
CommandObjectMemoryTagWrite::OptionGroupTagWrite::OptionParsingStarting
void OptionParsingStarting(ExecutionContext *execution_context) override
Definition: CommandObjectMemoryTag.cpp:168
CommandObjectMemoryTagWrite
Definition: CommandObjectMemoryTag.cpp:138
lldb_private::Range< lldb::addr_t, lldb::addr_t >
lldb_private::CommandInterpreter
Definition: CommandInterpreter.h:214
lldb_private::Process::GetMemoryTagManager
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:6111
CommandObjectMemoryTagRead::CommandObjectMemoryTagRead
CommandObjectMemoryTagRead(CommandInterpreter &interpreter)
Definition: CommandObjectMemoryTag.cpp:27
CommandObjectMemoryTagRead
Definition: CommandObjectMemoryTag.cpp:25
OptionValueString.h
CommandObjectMemoryTag.h
lldb_private::Status
Definition: Status.h:44
CommandObjectMemoryTagWrite::m_tag_write_options
OptionGroupTagWrite m_tag_write_options
Definition: CommandObjectMemoryTag.cpp:303
lldb_private::CommandReturnObject
Definition: CommandReturnObject.h:26
uint32_t
lldb::eReturnStatusSuccessFinishResult
@ eReturnStatusSuccessFinishResult
Definition: lldb-enumerations.h:262
lldb_private::CommandObjectMemoryTag::~CommandObjectMemoryTag
~CommandObjectMemoryTag() override
CommandObjectMemoryTagWrite::OptionGroupTagWrite::GetDefinitions
llvm::ArrayRef< OptionDefinition > GetDefinitions() override
Definition: CommandObjectMemoryTag.cpp:146
CommandObjectMemoryTagWrite::CommandObjectMemoryTagWrite
CommandObjectMemoryTagWrite(CommandInterpreter &interpreter)
Definition: CommandObjectMemoryTag.cpp:175
lldb_private::MemoryTagManager::GetGranuleSize
virtual lldb::addr_t GetGranuleSize() const =0
LLDB_INVALID_ADDRESS
#define LLDB_INVALID_ADDRESS
Definition: lldb-defines.h:74
CommandObjectMemoryTagRead::DoExecute
bool DoExecute(Args &command, CommandReturnObject &result) override
Definition: CommandObjectMemoryTag.cpp:45
lldb_private::CommandReturnObject::AppendErrorWithFormat
void AppendErrorWithFormat(const char *format,...) __attribute__((format(printf
Definition: CommandReturnObject.cpp:46
lldb_private::Process::ReadMemoryTags
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:6130
OptionParser.h
lldb_private
A class that represents a running process on the host machine.
Definition: SBCommandInterpreterRunOptions.h:16
lldb_private::Process::GetABI
const lldb::ABISP & GetABI()
Definition: Process.cpp:1486
CommandOptionArgumentTable.h
CommandObjectMemoryTagWrite::GetOptions
Options * GetOptions() override
Definition: CommandObjectMemoryTag.cpp:195
lldb_private::CommandObject::CommandArgumentEntry
std::vector< CommandArgumentData > CommandArgumentEntry
Definition: CommandObject.h:107
lldb_private::CommandReturnObject::AppendError
void void AppendError(llvm::StringRef in_string)
Definition: CommandReturnObject.cpp:100
lldb_private::Args::GetArgumentCount
size_t GetArgumentCount() const
Gets the number of arguments left in this command object.
Definition: Args.h:116
lldb
Definition: SBAddress.h:15
lldb_private::CommandReturnObject::AppendMessage
void AppendMessage(llvm::StringRef in_string)
Definition: CommandReturnObject.cpp:88
lldb_private::CommandReturnObject::AppendMessageWithFormatv
void void AppendMessageWithFormatv(const char *format, Args &&... args)
Definition: CommandReturnObject.h:120
lldb_private::Process::WriteMemoryTags
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:6146
CommandObjectMemoryTagWrite::OptionGroupTagWrite::SetOptionValue
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, ExecutionContext *execution_context) override
Definition: CommandObjectMemoryTag.cpp:150
lldb_private::MemoryTagManager::ExpandToGranule
virtual TagRange ExpandToGranule(TagRange range) const =0