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"
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 
25 public:
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(
36  // Optional end address
37  m_arguments.push_back(CommandArgumentEntry{
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(),
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 
130  return true;
131  }
132 };
133 
134 #define LLDB_OPTIONS_memory_tag_write
135 #include "CommandOptions.inc"
136 
138 public:
140  public:
141  OptionGroupTagWrite() = default;
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 
172  };
173 
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(
184  // One or more tag values
185  m_arguments.push_back(CommandArgumentEntry{
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 
298  return true;
299  }
300 
303 };
304 
305 CommandObjectMemoryTag::CommandObjectMemoryTag(CommandInterpreter &interpreter)
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 
CommandObjectMemoryTagWrite::m_option_group
OptionGroupOptions m_option_group
Definition: CommandObjectMemoryTag.cpp:301
lldb_private::eArgRepeatOptional
@ eArgRepeatOptional
Definition: lldb-private-enumerations.h:96
lldb_private::CommandObjectParsed
Definition: CommandObject.h:393
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:197
lldb_private::Args::Shift
void Shift()
Shifts the first argument C string value of the array off the argument array.
Definition: Args.cpp:281
lldb_private::Process
Definition: Process.h:338
lldb_private::OptionGroupOptions
Definition: Options.h:255
lldb_private::CommandObject::CommandArgumentData
Definition: CommandObject.h:89
lldb_private::Process::GetMemoryRegions
virtual Status GetMemoryRegions(lldb_private::MemoryRegionInfos &region_list)
Obtain all the mapped memory regions within this process.
Definition: Process.cpp:5860
lldb_private::OptionGroup
Definition: Options.h:233
lldb::eArgTypeAddressOrExpression
@ eArgTypeAddressOrExpression
Definition: lldb-enumerations.h:517
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:593
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:139
lldb_private::MemoryRegionInfos
Definition: MemoryRegionInfo.h:172
CommandObjectMemoryTagWrite::OptionGroupTagWrite::OptionParsingStarting
void OptionParsingStarting(ExecutionContext *execution_context) override
Definition: CommandObjectMemoryTag.cpp:167
CommandObjectMemoryTagWrite
Definition: CommandObjectMemoryTag.cpp:137
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:6087
CommandObjectMemoryTagRead::CommandObjectMemoryTagRead
CommandObjectMemoryTagRead(CommandInterpreter &interpreter)
Definition: CommandObjectMemoryTag.cpp:26
CommandObjectMemoryTagRead
Definition: CommandObjectMemoryTag.cpp:24
OptionValueString.h
CommandObjectMemoryTag.h
lldb_private::Status
Definition: Status.h:44
CommandObjectMemoryTagWrite::m_tag_write_options
OptionGroupTagWrite m_tag_write_options
Definition: CommandObjectMemoryTag.cpp:302
lldb_private::CommandReturnObject
Definition: CommandReturnObject.h:26
uint32_t
lldb::eReturnStatusSuccessFinishResult
@ eReturnStatusSuccessFinishResult
Definition: lldb-enumerations.h:261
lldb_private::CommandObjectMemoryTag::~CommandObjectMemoryTag
~CommandObjectMemoryTag() override
CommandObjectMemoryTagWrite::OptionGroupTagWrite::GetDefinitions
llvm::ArrayRef< OptionDefinition > GetDefinitions() override
Definition: CommandObjectMemoryTag.cpp:145
CommandObjectMemoryTagWrite::CommandObjectMemoryTagWrite
CommandObjectMemoryTagWrite(CommandInterpreter &interpreter)
Definition: CommandObjectMemoryTag.cpp:174
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:44
lldb_private::CommandReturnObject::AppendErrorWithFormat
void AppendErrorWithFormat(const char *format,...) __attribute__((format(printf
Definition: CommandReturnObject.cpp:46
lldb_private::Process::ReadMemoryTags
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:6106
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:1482
CommandObjectMemoryTagWrite::GetOptions
Options * GetOptions() override
Definition: CommandObjectMemoryTag.cpp:194
lldb_private::CommandObject::CommandArgumentEntry
std::vector< CommandArgumentData > CommandArgumentEntry
Definition: CommandObject.h:105
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:118
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:6122
CommandObjectMemoryTagWrite::OptionGroupTagWrite::SetOptionValue
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, ExecutionContext *execution_context) override
Definition: CommandObjectMemoryTag.cpp:149
lldb_private::MemoryTagManager::ExpandToGranule
virtual TagRange ExpandToGranule(TagRange range) const =0