xref: /src/contrib/llvm-project/lldb/source/Commands/CommandObjectMemory.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1cfca06d7SDimitry Andric //===-- CommandObjectMemory.cpp -------------------------------------------===//
2f034231aSEd Maste //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f034231aSEd Maste //
7f034231aSEd Maste //===----------------------------------------------------------------------===//
8f034231aSEd Maste 
9f3fbd1c0SDimitry Andric #include "CommandObjectMemory.h"
10344a3780SDimitry Andric #include "CommandObjectMemoryTag.h"
1174a628f7SDimitry Andric #include "lldb/Core/DumpDataExtractor.h"
12f3fbd1c0SDimitry Andric #include "lldb/Core/Section.h"
13f034231aSEd Maste #include "lldb/Core/ValueObjectMemory.h"
145f29bb8aSDimitry Andric #include "lldb/Expression/ExpressionVariable.h"
1574a628f7SDimitry Andric #include "lldb/Host/OptionParser.h"
164b4fe385SDimitry Andric #include "lldb/Interpreter/CommandOptionArgumentTable.h"
17f3fbd1c0SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h"
18f73363f1SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h"
19f034231aSEd Maste #include "lldb/Interpreter/OptionGroupFormat.h"
20145449b1SDimitry Andric #include "lldb/Interpreter/OptionGroupMemoryTag.h"
21f034231aSEd Maste #include "lldb/Interpreter/OptionGroupOutputFile.h"
22f034231aSEd Maste #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
235f29bb8aSDimitry Andric #include "lldb/Interpreter/OptionValueLanguage.h"
24f034231aSEd Maste #include "lldb/Interpreter/OptionValueString.h"
25f3fbd1c0SDimitry Andric #include "lldb/Interpreter/Options.h"
26f3fbd1c0SDimitry Andric #include "lldb/Symbol/SymbolFile.h"
27f034231aSEd Maste #include "lldb/Symbol/TypeList.h"
286f8fc217SDimitry Andric #include "lldb/Target/ABI.h"
295f29bb8aSDimitry Andric #include "lldb/Target/Language.h"
30205afe67SEd Maste #include "lldb/Target/MemoryHistory.h"
31f3fbd1c0SDimitry Andric #include "lldb/Target/MemoryRegionInfo.h"
32f034231aSEd Maste #include "lldb/Target/Process.h"
33f034231aSEd Maste #include "lldb/Target/StackFrame.h"
345f29bb8aSDimitry Andric #include "lldb/Target/Target.h"
35205afe67SEd Maste #include "lldb/Target/Thread.h"
36f73363f1SDimitry Andric #include "lldb/Utility/Args.h"
3774a628f7SDimitry Andric #include "lldb/Utility/DataBufferHeap.h"
3874a628f7SDimitry Andric #include "lldb/Utility/StreamString.h"
39b60736ecSDimitry Andric #include "llvm/Support/MathExtras.h"
405f29bb8aSDimitry Andric #include <cinttypes>
415f29bb8aSDimitry Andric #include <memory>
42e3b55780SDimitry Andric #include <optional>
435f29bb8aSDimitry Andric 
44f034231aSEd Maste using namespace lldb;
45f034231aSEd Maste using namespace lldb_private;
46f034231aSEd Maste 
47ead24645SDimitry Andric #define LLDB_OPTIONS_memory_read
48ead24645SDimitry Andric #include "CommandOptions.inc"
49f034231aSEd Maste 
5014f1b3e8SDimitry Andric class OptionGroupReadMemory : public OptionGroup {
51f034231aSEd Maste public:
OptionGroupReadMemory()5214f1b3e8SDimitry Andric   OptionGroupReadMemory()
536f8fc217SDimitry Andric       : m_num_per_line(1, 1), m_offset(0, 0),
54344a3780SDimitry Andric         m_language_for_type(eLanguageTypeUnknown) {}
55f034231aSEd Maste 
56f3fbd1c0SDimitry Andric   ~OptionGroupReadMemory() override = default;
57f034231aSEd Maste 
GetDefinitions()5814f1b3e8SDimitry Andric   llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
59e3b55780SDimitry Andric     return llvm::ArrayRef(g_memory_read_options);
60f034231aSEd Maste   }
61f034231aSEd Maste 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_value,ExecutionContext * execution_context)62b76161e4SDimitry Andric   Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
6314f1b3e8SDimitry Andric                         ExecutionContext *execution_context) override {
64b76161e4SDimitry Andric     Status error;
65ead24645SDimitry Andric     const int short_option = g_memory_read_options[option_idx].short_option;
66f034231aSEd Maste 
6714f1b3e8SDimitry Andric     switch (short_option) {
68f034231aSEd Maste     case 'l':
6914f1b3e8SDimitry Andric       error = m_num_per_line.SetValueFromString(option_value);
70f034231aSEd Maste       if (m_num_per_line.GetCurrentValue() == 0)
7114f1b3e8SDimitry Andric         error.SetErrorStringWithFormat(
7214f1b3e8SDimitry Andric             "invalid value for --num-per-line option '%s'",
7314f1b3e8SDimitry Andric             option_value.str().c_str());
74f034231aSEd Maste       break;
75f034231aSEd Maste 
76f034231aSEd Maste     case 'b':
77f034231aSEd Maste       m_output_as_binary = true;
78f034231aSEd Maste       break;
79f034231aSEd Maste 
80f034231aSEd Maste     case 't':
8114f1b3e8SDimitry Andric       error = m_view_as_type.SetValueFromString(option_value);
82f034231aSEd Maste       break;
83f034231aSEd Maste 
84f034231aSEd Maste     case 'r':
85f034231aSEd Maste       m_force = true;
86f034231aSEd Maste       break;
87f034231aSEd Maste 
885f29bb8aSDimitry Andric     case 'x':
895f29bb8aSDimitry Andric       error = m_language_for_type.SetValueFromString(option_value);
905f29bb8aSDimitry Andric       break;
915f29bb8aSDimitry Andric 
92e81d9d49SDimitry Andric     case 'E':
9314f1b3e8SDimitry Andric       error = m_offset.SetValueFromString(option_value);
94e81d9d49SDimitry Andric       break;
95e81d9d49SDimitry Andric 
96f034231aSEd Maste     default:
97ead24645SDimitry Andric       llvm_unreachable("Unimplemented option");
98f034231aSEd Maste     }
99f034231aSEd Maste     return error;
100f034231aSEd Maste   }
101f034231aSEd Maste 
OptionParsingStarting(ExecutionContext * execution_context)10214f1b3e8SDimitry Andric   void OptionParsingStarting(ExecutionContext *execution_context) override {
103f034231aSEd Maste     m_num_per_line.Clear();
104f034231aSEd Maste     m_output_as_binary = false;
105f034231aSEd Maste     m_view_as_type.Clear();
106f034231aSEd Maste     m_force = false;
107e81d9d49SDimitry Andric     m_offset.Clear();
1085f29bb8aSDimitry Andric     m_language_for_type.Clear();
109f034231aSEd Maste   }
110f034231aSEd Maste 
FinalizeSettings(Target * target,OptionGroupFormat & format_options)111b76161e4SDimitry Andric   Status FinalizeSettings(Target *target, OptionGroupFormat &format_options) {
112b76161e4SDimitry Andric     Status error;
113f034231aSEd Maste     OptionValueUInt64 &byte_size_value = format_options.GetByteSizeValue();
114f034231aSEd Maste     OptionValueUInt64 &count_value = format_options.GetCountValue();
115f034231aSEd Maste     const bool byte_size_option_set = byte_size_value.OptionWasSet();
116f034231aSEd Maste     const bool num_per_line_option_set = m_num_per_line.OptionWasSet();
117f034231aSEd Maste     const bool count_option_set = format_options.GetCountValue().OptionWasSet();
118f034231aSEd Maste 
11914f1b3e8SDimitry Andric     switch (format_options.GetFormat()) {
120f034231aSEd Maste     default:
121f034231aSEd Maste       break;
122f034231aSEd Maste 
123f034231aSEd Maste     case eFormatBoolean:
124f034231aSEd Maste       if (!byte_size_option_set)
125f034231aSEd Maste         byte_size_value = 1;
126f034231aSEd Maste       if (!num_per_line_option_set)
127f034231aSEd Maste         m_num_per_line = 1;
128f034231aSEd Maste       if (!count_option_set)
129f034231aSEd Maste         format_options.GetCountValue() = 8;
130f034231aSEd Maste       break;
131f034231aSEd Maste 
132f034231aSEd Maste     case eFormatCString:
133f034231aSEd Maste       break;
134f034231aSEd Maste 
135f034231aSEd Maste     case eFormatInstruction:
136f034231aSEd Maste       if (count_option_set)
137f034231aSEd Maste         byte_size_value = target->GetArchitecture().GetMaximumOpcodeByteSize();
138f034231aSEd Maste       m_num_per_line = 1;
139f034231aSEd Maste       break;
140f034231aSEd Maste 
141f034231aSEd Maste     case eFormatAddressInfo:
142f034231aSEd Maste       if (!byte_size_option_set)
143f034231aSEd Maste         byte_size_value = target->GetArchitecture().GetAddressByteSize();
144f034231aSEd Maste       m_num_per_line = 1;
145f034231aSEd Maste       if (!count_option_set)
146f034231aSEd Maste         format_options.GetCountValue() = 8;
147f034231aSEd Maste       break;
148f034231aSEd Maste 
149f034231aSEd Maste     case eFormatPointer:
150f034231aSEd Maste       byte_size_value = target->GetArchitecture().GetAddressByteSize();
151f034231aSEd Maste       if (!num_per_line_option_set)
152f034231aSEd Maste         m_num_per_line = 4;
153f034231aSEd Maste       if (!count_option_set)
154f034231aSEd Maste         format_options.GetCountValue() = 8;
155f034231aSEd Maste       break;
156f034231aSEd Maste 
157f034231aSEd Maste     case eFormatBinary:
158f034231aSEd Maste     case eFormatFloat:
159f034231aSEd Maste     case eFormatOctal:
160f034231aSEd Maste     case eFormatDecimal:
161f034231aSEd Maste     case eFormatEnum:
162ead24645SDimitry Andric     case eFormatUnicode8:
163f034231aSEd Maste     case eFormatUnicode16:
164f034231aSEd Maste     case eFormatUnicode32:
165f034231aSEd Maste     case eFormatUnsigned:
166f034231aSEd Maste     case eFormatHexFloat:
167f034231aSEd Maste       if (!byte_size_option_set)
168f034231aSEd Maste         byte_size_value = 4;
169f034231aSEd Maste       if (!num_per_line_option_set)
170f034231aSEd Maste         m_num_per_line = 1;
171f034231aSEd Maste       if (!count_option_set)
172f034231aSEd Maste         format_options.GetCountValue() = 8;
173f034231aSEd Maste       break;
174f034231aSEd Maste 
175f034231aSEd Maste     case eFormatBytes:
176f034231aSEd Maste     case eFormatBytesWithASCII:
17714f1b3e8SDimitry Andric       if (byte_size_option_set) {
178f034231aSEd Maste         if (byte_size_value > 1)
179f3fbd1c0SDimitry Andric           error.SetErrorStringWithFormat(
18014f1b3e8SDimitry Andric               "display format (bytes/bytes with ASCII) conflicts with the "
18114f1b3e8SDimitry Andric               "specified byte size %" PRIu64 "\n"
18214f1b3e8SDimitry Andric               "\tconsider using a different display format or don't specify "
18314f1b3e8SDimitry Andric               "the byte size.",
184f034231aSEd Maste               byte_size_value.GetCurrentValue());
18514f1b3e8SDimitry Andric       } else
186f034231aSEd Maste         byte_size_value = 1;
187f034231aSEd Maste       if (!num_per_line_option_set)
188f034231aSEd Maste         m_num_per_line = 16;
189f034231aSEd Maste       if (!count_option_set)
190f034231aSEd Maste         format_options.GetCountValue() = 32;
191f034231aSEd Maste       break;
192f3fbd1c0SDimitry Andric 
193f034231aSEd Maste     case eFormatCharArray:
194f034231aSEd Maste     case eFormatChar:
195f034231aSEd Maste     case eFormatCharPrintable:
196f034231aSEd Maste       if (!byte_size_option_set)
197f034231aSEd Maste         byte_size_value = 1;
198f034231aSEd Maste       if (!num_per_line_option_set)
199f034231aSEd Maste         m_num_per_line = 32;
200f034231aSEd Maste       if (!count_option_set)
201f034231aSEd Maste         format_options.GetCountValue() = 64;
202f034231aSEd Maste       break;
203f3fbd1c0SDimitry Andric 
204f034231aSEd Maste     case eFormatComplex:
205f034231aSEd Maste       if (!byte_size_option_set)
206f034231aSEd Maste         byte_size_value = 8;
207f034231aSEd Maste       if (!num_per_line_option_set)
208f034231aSEd Maste         m_num_per_line = 1;
209f034231aSEd Maste       if (!count_option_set)
210f034231aSEd Maste         format_options.GetCountValue() = 8;
211f034231aSEd Maste       break;
212f3fbd1c0SDimitry Andric 
213f034231aSEd Maste     case eFormatComplexInteger:
214f034231aSEd Maste       if (!byte_size_option_set)
215f034231aSEd Maste         byte_size_value = 8;
216f034231aSEd Maste       if (!num_per_line_option_set)
217f034231aSEd Maste         m_num_per_line = 1;
218f034231aSEd Maste       if (!count_option_set)
219f034231aSEd Maste         format_options.GetCountValue() = 8;
220f034231aSEd Maste       break;
221f3fbd1c0SDimitry Andric 
222f034231aSEd Maste     case eFormatHex:
223f034231aSEd Maste       if (!byte_size_option_set)
224f034231aSEd Maste         byte_size_value = 4;
22514f1b3e8SDimitry Andric       if (!num_per_line_option_set) {
22614f1b3e8SDimitry Andric         switch (byte_size_value) {
227f034231aSEd Maste         case 1:
228f034231aSEd Maste         case 2:
229f034231aSEd Maste           m_num_per_line = 8;
230f034231aSEd Maste           break;
231f034231aSEd Maste         case 4:
232f034231aSEd Maste           m_num_per_line = 4;
233f034231aSEd Maste           break;
234f034231aSEd Maste         case 8:
235f034231aSEd Maste           m_num_per_line = 2;
236f034231aSEd Maste           break;
237f034231aSEd Maste         default:
238f034231aSEd Maste           m_num_per_line = 1;
239f034231aSEd Maste           break;
240f034231aSEd Maste         }
241f034231aSEd Maste       }
242f034231aSEd Maste       if (!count_option_set)
243f034231aSEd Maste         count_value = 8;
244f034231aSEd Maste       break;
245f034231aSEd Maste 
246f034231aSEd Maste     case eFormatVectorOfChar:
247f034231aSEd Maste     case eFormatVectorOfSInt8:
248f034231aSEd Maste     case eFormatVectorOfUInt8:
249f034231aSEd Maste     case eFormatVectorOfSInt16:
250f034231aSEd Maste     case eFormatVectorOfUInt16:
251f034231aSEd Maste     case eFormatVectorOfSInt32:
252f034231aSEd Maste     case eFormatVectorOfUInt32:
253f034231aSEd Maste     case eFormatVectorOfSInt64:
254f034231aSEd Maste     case eFormatVectorOfUInt64:
255e81d9d49SDimitry Andric     case eFormatVectorOfFloat16:
256f034231aSEd Maste     case eFormatVectorOfFloat32:
257f034231aSEd Maste     case eFormatVectorOfFloat64:
258f034231aSEd Maste     case eFormatVectorOfUInt128:
259f034231aSEd Maste       if (!byte_size_option_set)
260f034231aSEd Maste         byte_size_value = 128;
261f034231aSEd Maste       if (!num_per_line_option_set)
262f034231aSEd Maste         m_num_per_line = 1;
263f034231aSEd Maste       if (!count_option_set)
264f034231aSEd Maste         count_value = 4;
265f034231aSEd Maste       break;
266f034231aSEd Maste     }
267f034231aSEd Maste     return error;
268f034231aSEd Maste   }
269f034231aSEd Maste 
AnyOptionWasSet() const27014f1b3e8SDimitry Andric   bool AnyOptionWasSet() const {
27114f1b3e8SDimitry Andric     return m_num_per_line.OptionWasSet() || m_output_as_binary ||
2725f29bb8aSDimitry Andric            m_view_as_type.OptionWasSet() || m_offset.OptionWasSet() ||
2735f29bb8aSDimitry Andric            m_language_for_type.OptionWasSet();
274f034231aSEd Maste   }
275f034231aSEd Maste 
276f034231aSEd Maste   OptionValueUInt64 m_num_per_line;
277344a3780SDimitry Andric   bool m_output_as_binary = false;
278f034231aSEd Maste   OptionValueString m_view_as_type;
2794b4fe385SDimitry Andric   bool m_force = false;
280e81d9d49SDimitry Andric   OptionValueUInt64 m_offset;
2815f29bb8aSDimitry Andric   OptionValueLanguage m_language_for_type;
282f034231aSEd Maste };
283f034231aSEd Maste 
284f034231aSEd Maste // Read memory from the inferior process
28514f1b3e8SDimitry Andric class CommandObjectMemoryRead : public CommandObjectParsed {
286f034231aSEd Maste public:
CommandObjectMemoryRead(CommandInterpreter & interpreter)287f3fbd1c0SDimitry Andric   CommandObjectMemoryRead(CommandInterpreter &interpreter)
28814f1b3e8SDimitry Andric       : CommandObjectParsed(
28914f1b3e8SDimitry Andric             interpreter, "memory read",
29014f1b3e8SDimitry Andric             "Read from the memory of the current target process.", nullptr,
29114f1b3e8SDimitry Andric             eCommandRequiresTarget | eCommandProcessMustBePaused),
2926f8fc217SDimitry Andric         m_format_options(eFormatBytesWithASCII, 1, 8),
293145449b1SDimitry Andric         m_memory_tag_options(/*note_binary=*/true),
2946f8fc217SDimitry Andric         m_prev_format_options(eFormatBytesWithASCII, 1, 8) {
295f034231aSEd Maste     CommandArgumentEntry arg1;
296f034231aSEd Maste     CommandArgumentEntry arg2;
297f034231aSEd Maste     CommandArgumentData start_addr_arg;
298f034231aSEd Maste     CommandArgumentData end_addr_arg;
299f034231aSEd Maste 
300f034231aSEd Maste     // Define the first (and only) variant of this arg.
301f034231aSEd Maste     start_addr_arg.arg_type = eArgTypeAddressOrExpression;
302f034231aSEd Maste     start_addr_arg.arg_repetition = eArgRepeatPlain;
303f034231aSEd Maste 
30414f1b3e8SDimitry Andric     // There is only one variant this argument could be; put it into the
30514f1b3e8SDimitry Andric     // argument entry.
306f034231aSEd Maste     arg1.push_back(start_addr_arg);
307f034231aSEd Maste 
308f034231aSEd Maste     // Define the first (and only) variant of this arg.
309f034231aSEd Maste     end_addr_arg.arg_type = eArgTypeAddressOrExpression;
310f034231aSEd Maste     end_addr_arg.arg_repetition = eArgRepeatOptional;
311f034231aSEd Maste 
31214f1b3e8SDimitry Andric     // There is only one variant this argument could be; put it into the
31314f1b3e8SDimitry Andric     // argument entry.
314f034231aSEd Maste     arg2.push_back(end_addr_arg);
315f034231aSEd Maste 
316f034231aSEd Maste     // Push the data for the first argument into the m_arguments vector.
317f034231aSEd Maste     m_arguments.push_back(arg1);
318f034231aSEd Maste     m_arguments.push_back(arg2);
319f034231aSEd Maste 
320f034231aSEd Maste     // Add the "--format" and "--count" options to group 1 and 3
321f034231aSEd Maste     m_option_group.Append(&m_format_options,
32214f1b3e8SDimitry Andric                           OptionGroupFormat::OPTION_GROUP_FORMAT |
32314f1b3e8SDimitry Andric                               OptionGroupFormat::OPTION_GROUP_COUNT,
324f034231aSEd Maste                           LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3);
325f034231aSEd Maste     m_option_group.Append(&m_format_options,
326f034231aSEd Maste                           OptionGroupFormat::OPTION_GROUP_GDB_FMT,
327f034231aSEd Maste                           LLDB_OPT_SET_1 | LLDB_OPT_SET_3);
328f034231aSEd Maste     // Add the "--size" option to group 1 and 2
329f034231aSEd Maste     m_option_group.Append(&m_format_options,
330f034231aSEd Maste                           OptionGroupFormat::OPTION_GROUP_SIZE,
331f034231aSEd Maste                           LLDB_OPT_SET_1 | LLDB_OPT_SET_2);
332f034231aSEd Maste     m_option_group.Append(&m_memory_options);
33314f1b3e8SDimitry Andric     m_option_group.Append(&m_outfile_options, LLDB_OPT_SET_ALL,
33414f1b3e8SDimitry Andric                           LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3);
335f034231aSEd Maste     m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_3);
336145449b1SDimitry Andric     m_option_group.Append(&m_memory_tag_options, LLDB_OPT_SET_ALL,
337145449b1SDimitry Andric                           LLDB_OPT_SET_ALL);
338f034231aSEd Maste     m_option_group.Finalize();
339f034231aSEd Maste   }
340f034231aSEd Maste 
341f3fbd1c0SDimitry Andric   ~CommandObjectMemoryRead() override = default;
342f034231aSEd Maste 
GetOptions()34314f1b3e8SDimitry Andric   Options *GetOptions() override { return &m_option_group; }
344f034231aSEd Maste 
GetRepeatCommand(Args & current_command_args,uint32_t index)345e3b55780SDimitry Andric   std::optional<std::string> GetRepeatCommand(Args &current_command_args,
34614f1b3e8SDimitry Andric                                               uint32_t index) override {
347145449b1SDimitry Andric     return m_cmd_name;
348f034231aSEd Maste   }
349f034231aSEd Maste 
350f034231aSEd Maste protected:
DoExecute(Args & command,CommandReturnObject & result)351b1c73532SDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
35214f1b3e8SDimitry Andric     // No need to check "target" for validity as eCommandRequiresTarget ensures
35314f1b3e8SDimitry Andric     // it is valid
354f034231aSEd Maste     Target *target = m_exe_ctx.GetTargetPtr();
355f034231aSEd Maste 
356f034231aSEd Maste     const size_t argc = command.GetArgumentCount();
357f034231aSEd Maste 
35814f1b3e8SDimitry Andric     if ((argc == 0 && m_next_addr == LLDB_INVALID_ADDRESS) || argc > 2) {
35914f1b3e8SDimitry Andric       result.AppendErrorWithFormat("%s takes a start address expression with "
36014f1b3e8SDimitry Andric                                    "an optional end address expression.\n",
36114f1b3e8SDimitry Andric                                    m_cmd_name.c_str());
362344a3780SDimitry Andric       result.AppendWarning("Expressions should be quoted if they contain "
363344a3780SDimitry Andric                            "spaces or other special characters.");
364b1c73532SDimitry Andric       return;
365f034231aSEd Maste     }
366f034231aSEd Maste 
3675f29bb8aSDimitry Andric     CompilerType compiler_type;
368b76161e4SDimitry Andric     Status error;
369f034231aSEd Maste 
37014f1b3e8SDimitry Andric     const char *view_as_type_cstr =
37114f1b3e8SDimitry Andric         m_memory_options.m_view_as_type.GetCurrentValue();
37214f1b3e8SDimitry Andric     if (view_as_type_cstr && view_as_type_cstr[0]) {
373f034231aSEd Maste       // We are viewing memory as a type
374f034231aSEd Maste 
375f034231aSEd Maste       uint32_t reference_count = 0;
376f034231aSEd Maste       uint32_t pointer_count = 0;
377f034231aSEd Maste       size_t idx;
378f034231aSEd Maste 
379f034231aSEd Maste #define ALL_KEYWORDS                                                           \
380f034231aSEd Maste   KEYWORD("const")                                                             \
381f034231aSEd Maste   KEYWORD("volatile")                                                          \
382f034231aSEd Maste   KEYWORD("restrict")                                                          \
383f034231aSEd Maste   KEYWORD("struct")                                                            \
384f034231aSEd Maste   KEYWORD("class")                                                             \
385f034231aSEd Maste   KEYWORD("union")
386f034231aSEd Maste 
387f034231aSEd Maste #define KEYWORD(s) s,
38814f1b3e8SDimitry Andric       static const char *g_keywords[] = {ALL_KEYWORDS};
389f034231aSEd Maste #undef KEYWORD
390f034231aSEd Maste 
391f034231aSEd Maste #define KEYWORD(s) (sizeof(s) - 1),
39214f1b3e8SDimitry Andric       static const int g_keyword_lengths[] = {ALL_KEYWORDS};
393f034231aSEd Maste #undef KEYWORD
394f034231aSEd Maste 
395f034231aSEd Maste #undef ALL_KEYWORDS
396f034231aSEd Maste 
397f034231aSEd Maste       static size_t g_num_keywords = sizeof(g_keywords) / sizeof(const char *);
398f034231aSEd Maste       std::string type_str(view_as_type_cstr);
399f034231aSEd Maste 
400f034231aSEd Maste       // Remove all instances of g_keywords that are followed by spaces
40114f1b3e8SDimitry Andric       for (size_t i = 0; i < g_num_keywords; ++i) {
402f034231aSEd Maste         const char *keyword = g_keywords[i];
403f034231aSEd Maste         int keyword_len = g_keyword_lengths[i];
404f034231aSEd Maste 
405f034231aSEd Maste         idx = 0;
40614f1b3e8SDimitry Andric         while ((idx = type_str.find(keyword, idx)) != std::string::npos) {
40714f1b3e8SDimitry Andric           if (type_str[idx + keyword_len] == ' ' ||
40814f1b3e8SDimitry Andric               type_str[idx + keyword_len] == '\t') {
409f034231aSEd Maste             type_str.erase(idx, keyword_len + 1);
410f034231aSEd Maste             idx = 0;
41114f1b3e8SDimitry Andric           } else {
412f034231aSEd Maste             idx += keyword_len;
413f034231aSEd Maste           }
414f034231aSEd Maste         }
415f034231aSEd Maste       }
416f034231aSEd Maste       bool done = type_str.empty();
417f034231aSEd Maste       //
418f034231aSEd Maste       idx = type_str.find_first_not_of(" \t");
419f034231aSEd Maste       if (idx > 0 && idx != std::string::npos)
420f034231aSEd Maste         type_str.erase(0, idx);
42114f1b3e8SDimitry Andric       while (!done) {
422f034231aSEd Maste         // Strip trailing spaces
423f034231aSEd Maste         if (type_str.empty())
424f034231aSEd Maste           done = true;
42514f1b3e8SDimitry Andric         else {
42614f1b3e8SDimitry Andric           switch (type_str[type_str.size() - 1]) {
427f034231aSEd Maste           case '*':
428f034231aSEd Maste             ++pointer_count;
429e3b55780SDimitry Andric             [[fallthrough]];
430f034231aSEd Maste           case ' ':
431f034231aSEd Maste           case '\t':
432f034231aSEd Maste             type_str.erase(type_str.size() - 1);
433f034231aSEd Maste             break;
434f034231aSEd Maste 
435f034231aSEd Maste           case '&':
43614f1b3e8SDimitry Andric             if (reference_count == 0) {
437f034231aSEd Maste               reference_count = 1;
438f034231aSEd Maste               type_str.erase(type_str.size() - 1);
43914f1b3e8SDimitry Andric             } else {
44014f1b3e8SDimitry Andric               result.AppendErrorWithFormat("invalid type string: '%s'\n",
44114f1b3e8SDimitry Andric                                            view_as_type_cstr);
442b1c73532SDimitry Andric               return;
443f034231aSEd Maste             }
444f034231aSEd Maste             break;
445f034231aSEd Maste 
446f034231aSEd Maste           default:
447f034231aSEd Maste             done = true;
448f034231aSEd Maste             break;
449f034231aSEd Maste           }
450f034231aSEd Maste         }
451f034231aSEd Maste       }
452f034231aSEd Maste 
453f034231aSEd Maste       ConstString lookup_type_name(type_str.c_str());
454f034231aSEd Maste       StackFrame *frame = m_exe_ctx.GetFramePtr();
45594994d37SDimitry Andric       ModuleSP search_first;
456312c0ed1SDimitry Andric       if (frame)
45794994d37SDimitry Andric         search_first = frame->GetSymbolContext(eSymbolContextModule).module_sp;
458312c0ed1SDimitry Andric       TypeQuery query(lookup_type_name.GetStringRef(),
459312c0ed1SDimitry Andric                       TypeQueryOptions::e_find_one);
460312c0ed1SDimitry Andric       TypeResults results;
461312c0ed1SDimitry Andric       target->GetImages().FindTypes(search_first.get(), query, results);
462312c0ed1SDimitry Andric       TypeSP type_sp = results.GetFirstType();
463f034231aSEd Maste 
464312c0ed1SDimitry Andric       if (!type_sp && lookup_type_name.GetCString()) {
4655f29bb8aSDimitry Andric         LanguageType language_for_type =
4665f29bb8aSDimitry Andric             m_memory_options.m_language_for_type.GetCurrentValue();
4675f29bb8aSDimitry Andric         std::set<LanguageType> languages_to_check;
4685f29bb8aSDimitry Andric         if (language_for_type != eLanguageTypeUnknown) {
4695f29bb8aSDimitry Andric           languages_to_check.insert(language_for_type);
4705f29bb8aSDimitry Andric         } else {
4715f29bb8aSDimitry Andric           languages_to_check = Language::GetSupportedLanguages();
4725f29bb8aSDimitry Andric         }
473e81d9d49SDimitry Andric 
4745f29bb8aSDimitry Andric         std::set<CompilerType> user_defined_types;
4755f29bb8aSDimitry Andric         for (auto lang : languages_to_check) {
4765f29bb8aSDimitry Andric           if (auto *persistent_vars =
4775f29bb8aSDimitry Andric                   target->GetPersistentExpressionStateForLanguage(lang)) {
478e3b55780SDimitry Andric             if (std::optional<CompilerType> type =
4795f29bb8aSDimitry Andric                     persistent_vars->GetCompilerTypeFromPersistentDecl(
4805f29bb8aSDimitry Andric                         lookup_type_name)) {
4815f29bb8aSDimitry Andric               user_defined_types.emplace(*type);
482e81d9d49SDimitry Andric             }
483f034231aSEd Maste           }
484f034231aSEd Maste         }
485f034231aSEd Maste 
4865f29bb8aSDimitry Andric         if (user_defined_types.size() > 1) {
4875f29bb8aSDimitry Andric           result.AppendErrorWithFormat(
4885f29bb8aSDimitry Andric               "Mutiple types found matching raw type '%s', please disambiguate "
4895f29bb8aSDimitry Andric               "by specifying the language with -x",
4905f29bb8aSDimitry Andric               lookup_type_name.GetCString());
491b1c73532SDimitry Andric           return;
4925f29bb8aSDimitry Andric         }
4935f29bb8aSDimitry Andric 
4945f29bb8aSDimitry Andric         if (user_defined_types.size() == 1) {
4955f29bb8aSDimitry Andric           compiler_type = *user_defined_types.begin();
4965f29bb8aSDimitry Andric         }
4975f29bb8aSDimitry Andric       }
4985f29bb8aSDimitry Andric 
4995f29bb8aSDimitry Andric       if (!compiler_type.IsValid()) {
500312c0ed1SDimitry Andric         if (type_sp) {
501312c0ed1SDimitry Andric           compiler_type = type_sp->GetFullCompilerType();
502312c0ed1SDimitry Andric         } else {
50314f1b3e8SDimitry Andric           result.AppendErrorWithFormat("unable to find any types that match "
50414f1b3e8SDimitry Andric                                        "the raw type '%s' for full type '%s'\n",
505f034231aSEd Maste                                        lookup_type_name.GetCString(),
506f034231aSEd Maste                                        view_as_type_cstr);
507b1c73532SDimitry Andric           return;
508f034231aSEd Maste         }
509f034231aSEd Maste       }
510f034231aSEd Maste 
51114f1b3e8SDimitry Andric       while (pointer_count > 0) {
5125f29bb8aSDimitry Andric         CompilerType pointer_type = compiler_type.GetPointerType();
513f034231aSEd Maste         if (pointer_type.IsValid())
5145f29bb8aSDimitry Andric           compiler_type = pointer_type;
51514f1b3e8SDimitry Andric         else {
516f034231aSEd Maste           result.AppendError("unable make a pointer type\n");
517b1c73532SDimitry Andric           return;
518f034231aSEd Maste         }
519f034231aSEd Maste         --pointer_count;
520f034231aSEd Maste       }
521f034231aSEd Maste 
522e3b55780SDimitry Andric       std::optional<uint64_t> size = compiler_type.GetByteSize(nullptr);
52394994d37SDimitry Andric       if (!size) {
52414f1b3e8SDimitry Andric         result.AppendErrorWithFormat(
52514f1b3e8SDimitry Andric             "unable to get the byte size of the type '%s'\n",
526f034231aSEd Maste             view_as_type_cstr);
527b1c73532SDimitry Andric         return;
528f034231aSEd Maste       }
52994994d37SDimitry Andric       m_format_options.GetByteSizeValue() = *size;
530f034231aSEd Maste 
531f034231aSEd Maste       if (!m_format_options.GetCountValue().OptionWasSet())
532f034231aSEd Maste         m_format_options.GetCountValue() = 1;
53314f1b3e8SDimitry Andric     } else {
534f034231aSEd Maste       error = m_memory_options.FinalizeSettings(target, m_format_options);
535f034231aSEd Maste     }
536f034231aSEd Maste 
537f034231aSEd Maste     // Look for invalid combinations of settings
53814f1b3e8SDimitry Andric     if (error.Fail()) {
539f034231aSEd Maste       result.AppendError(error.AsCString());
540b1c73532SDimitry Andric       return;
541f034231aSEd Maste     }
542f034231aSEd Maste 
543f034231aSEd Maste     lldb::addr_t addr;
544f034231aSEd Maste     size_t total_byte_size = 0;
54514f1b3e8SDimitry Andric     if (argc == 0) {
546f73363f1SDimitry Andric       // Use the last address and byte size and all options as they were if no
547f73363f1SDimitry Andric       // options have been set
548f034231aSEd Maste       addr = m_next_addr;
549f034231aSEd Maste       total_byte_size = m_prev_byte_size;
5505f29bb8aSDimitry Andric       compiler_type = m_prev_compiler_type;
551f034231aSEd Maste       if (!m_format_options.AnyOptionWasSet() &&
552f034231aSEd Maste           !m_memory_options.AnyOptionWasSet() &&
553f034231aSEd Maste           !m_outfile_options.AnyOptionWasSet() &&
554145449b1SDimitry Andric           !m_varobj_options.AnyOptionWasSet() &&
555145449b1SDimitry Andric           !m_memory_tag_options.AnyOptionWasSet()) {
556f034231aSEd Maste         m_format_options = m_prev_format_options;
557f034231aSEd Maste         m_memory_options = m_prev_memory_options;
558f034231aSEd Maste         m_outfile_options = m_prev_outfile_options;
559f034231aSEd Maste         m_varobj_options = m_prev_varobj_options;
560145449b1SDimitry Andric         m_memory_tag_options = m_prev_memory_tag_options;
561f034231aSEd Maste       }
562f034231aSEd Maste     }
563f034231aSEd Maste 
564f034231aSEd Maste     size_t item_count = m_format_options.GetCountValue().GetCurrentValue();
565205afe67SEd Maste 
566205afe67SEd Maste     // TODO For non-8-bit byte addressable architectures this needs to be
567205afe67SEd Maste     // revisited to fully support all lldb's range of formatting options.
568f73363f1SDimitry Andric     // Furthermore code memory reads (for those architectures) will not be
569f73363f1SDimitry Andric     // correctly formatted even w/o formatting options.
570205afe67SEd Maste     size_t item_byte_size =
57114f1b3e8SDimitry Andric         target->GetArchitecture().GetDataByteSize() > 1
57214f1b3e8SDimitry Andric             ? target->GetArchitecture().GetDataByteSize()
57314f1b3e8SDimitry Andric             : m_format_options.GetByteSizeValue().GetCurrentValue();
574205afe67SEd Maste 
57514f1b3e8SDimitry Andric     const size_t num_per_line =
57614f1b3e8SDimitry Andric         m_memory_options.m_num_per_line.GetCurrentValue();
577f034231aSEd Maste 
57814f1b3e8SDimitry Andric     if (total_byte_size == 0) {
579f034231aSEd Maste       total_byte_size = item_count * item_byte_size;
580f034231aSEd Maste       if (total_byte_size == 0)
581f034231aSEd Maste         total_byte_size = 32;
582f034231aSEd Maste     }
583f034231aSEd Maste 
584f034231aSEd Maste     if (argc > 0)
585ead24645SDimitry Andric       addr = OptionArgParser::ToAddress(&m_exe_ctx, command[0].ref(),
58614f1b3e8SDimitry Andric                                         LLDB_INVALID_ADDRESS, &error);
587f034231aSEd Maste 
58814f1b3e8SDimitry Andric     if (addr == LLDB_INVALID_ADDRESS) {
589f034231aSEd Maste       result.AppendError("invalid start address expression.");
590f034231aSEd Maste       result.AppendError(error.AsCString());
591b1c73532SDimitry Andric       return;
592f034231aSEd Maste     }
593f034231aSEd Maste 
59414f1b3e8SDimitry Andric     if (argc == 2) {
595f73363f1SDimitry Andric       lldb::addr_t end_addr = OptionArgParser::ToAddress(
596ead24645SDimitry Andric           &m_exe_ctx, command[1].ref(), LLDB_INVALID_ADDRESS, nullptr);
5976f8fc217SDimitry Andric 
59814f1b3e8SDimitry Andric       if (end_addr == LLDB_INVALID_ADDRESS) {
599f034231aSEd Maste         result.AppendError("invalid end address expression.");
600f034231aSEd Maste         result.AppendError(error.AsCString());
601b1c73532SDimitry Andric         return;
60214f1b3e8SDimitry Andric       } else if (end_addr <= addr) {
60314f1b3e8SDimitry Andric         result.AppendErrorWithFormat(
60414f1b3e8SDimitry Andric             "end address (0x%" PRIx64
605344a3780SDimitry Andric             ") must be greater than the start address (0x%" PRIx64 ").\n",
60614f1b3e8SDimitry Andric             end_addr, addr);
607b1c73532SDimitry Andric         return;
60814f1b3e8SDimitry Andric       } else if (m_format_options.GetCountValue().OptionWasSet()) {
60914f1b3e8SDimitry Andric         result.AppendErrorWithFormat(
61014f1b3e8SDimitry Andric             "specify either the end address (0x%" PRIx64
61114f1b3e8SDimitry Andric             ") or the count (--count %" PRIu64 "), not both.\n",
61214f1b3e8SDimitry Andric             end_addr, (uint64_t)item_count);
613b1c73532SDimitry Andric         return;
614f034231aSEd Maste       }
615f034231aSEd Maste 
616f034231aSEd Maste       total_byte_size = end_addr - addr;
617f034231aSEd Maste       item_count = total_byte_size / item_byte_size;
618f034231aSEd Maste     }
619f034231aSEd Maste 
620f034231aSEd Maste     uint32_t max_unforced_size = target->GetMaximumMemReadSize();
621f034231aSEd Maste 
62214f1b3e8SDimitry Andric     if (total_byte_size > max_unforced_size && !m_memory_options.m_force) {
62314f1b3e8SDimitry Andric       result.AppendErrorWithFormat(
62414f1b3e8SDimitry Andric           "Normally, \'memory read\' will not read over %" PRIu32
62514f1b3e8SDimitry Andric           " bytes of data.\n",
62614f1b3e8SDimitry Andric           max_unforced_size);
62714f1b3e8SDimitry Andric       result.AppendErrorWithFormat(
62814f1b3e8SDimitry Andric           "Please use --force to override this restriction just once.\n");
62914f1b3e8SDimitry Andric       result.AppendErrorWithFormat("or set target.max-memory-read-size if you "
63014f1b3e8SDimitry Andric                                    "will often need a larger limit.\n");
631b1c73532SDimitry Andric       return;
632f034231aSEd Maste     }
633f034231aSEd Maste 
634145449b1SDimitry Andric     WritableDataBufferSP data_sp;
635f034231aSEd Maste     size_t bytes_read = 0;
6365f29bb8aSDimitry Andric     if (compiler_type.GetOpaqueQualType()) {
63714f1b3e8SDimitry Andric       // Make sure we don't display our type as ASCII bytes like the default
63814f1b3e8SDimitry Andric       // memory read
639f3fbd1c0SDimitry Andric       if (!m_format_options.GetFormatValue().OptionWasSet())
640f034231aSEd Maste         m_format_options.GetFormatValue().SetCurrentValue(eFormatDefault);
641f034231aSEd Maste 
642e3b55780SDimitry Andric       std::optional<uint64_t> size = compiler_type.GetByteSize(nullptr);
64394994d37SDimitry Andric       if (!size) {
64494994d37SDimitry Andric         result.AppendError("can't get size of type");
645b1c73532SDimitry Andric         return;
64694994d37SDimitry Andric       }
64794994d37SDimitry Andric       bytes_read = *size * m_format_options.GetCountValue().GetCurrentValue();
648e81d9d49SDimitry Andric 
649e81d9d49SDimitry Andric       if (argc > 0)
65094994d37SDimitry Andric         addr = addr + (*size * m_memory_options.m_offset.GetCurrentValue());
65114f1b3e8SDimitry Andric     } else if (m_format_options.GetFormatValue().GetCurrentValue() !=
65214f1b3e8SDimitry Andric                eFormatCString) {
6535f29bb8aSDimitry Andric       data_sp = std::make_shared<DataBufferHeap>(total_byte_size, '\0');
65414f1b3e8SDimitry Andric       if (data_sp->GetBytes() == nullptr) {
65514f1b3e8SDimitry Andric         result.AppendErrorWithFormat(
65614f1b3e8SDimitry Andric             "can't allocate 0x%" PRIx32
65714f1b3e8SDimitry Andric             " bytes for the memory read buffer, specify a smaller size to read",
65814f1b3e8SDimitry Andric             (uint32_t)total_byte_size);
659b1c73532SDimitry Andric         return;
660f034231aSEd Maste       }
661f034231aSEd Maste 
662f3fbd1c0SDimitry Andric       Address address(addr, nullptr);
663344a3780SDimitry Andric       bytes_read = target->ReadMemory(address, data_sp->GetBytes(),
664344a3780SDimitry Andric                                       data_sp->GetByteSize(), error, true);
66514f1b3e8SDimitry Andric       if (bytes_read == 0) {
666f034231aSEd Maste         const char *error_cstr = error.AsCString();
66714f1b3e8SDimitry Andric         if (error_cstr && error_cstr[0]) {
668f034231aSEd Maste           result.AppendError(error_cstr);
66914f1b3e8SDimitry Andric         } else {
67014f1b3e8SDimitry Andric           result.AppendErrorWithFormat(
67114f1b3e8SDimitry Andric               "failed to read memory from 0x%" PRIx64 ".\n", addr);
672f034231aSEd Maste         }
673b1c73532SDimitry Andric         return;
674f034231aSEd Maste       }
675f034231aSEd Maste 
676f034231aSEd Maste       if (bytes_read < total_byte_size)
67714f1b3e8SDimitry Andric         result.AppendWarningWithFormat(
67814f1b3e8SDimitry Andric             "Not all bytes (%" PRIu64 "/%" PRIu64
67914f1b3e8SDimitry Andric             ") were able to be read from 0x%" PRIx64 ".\n",
68014f1b3e8SDimitry Andric             (uint64_t)bytes_read, (uint64_t)total_byte_size, addr);
68114f1b3e8SDimitry Andric     } else {
68214f1b3e8SDimitry Andric       // we treat c-strings as a special case because they do not have a fixed
68314f1b3e8SDimitry Andric       // size
68414f1b3e8SDimitry Andric       if (m_format_options.GetByteSizeValue().OptionWasSet() &&
68514f1b3e8SDimitry Andric           !m_format_options.HasGDBFormat())
686f034231aSEd Maste         item_byte_size = m_format_options.GetByteSizeValue().GetCurrentValue();
687f034231aSEd Maste       else
688f034231aSEd Maste         item_byte_size = target->GetMaximumSizeOfStringSummary();
689f034231aSEd Maste       if (!m_format_options.GetCountValue().OptionWasSet())
690f034231aSEd Maste         item_count = 1;
6915f29bb8aSDimitry Andric       data_sp = std::make_shared<DataBufferHeap>(
6925f29bb8aSDimitry Andric           (item_byte_size + 1) * item_count,
6935f29bb8aSDimitry Andric           '\0'); // account for NULLs as necessary
69414f1b3e8SDimitry Andric       if (data_sp->GetBytes() == nullptr) {
69514f1b3e8SDimitry Andric         result.AppendErrorWithFormat(
69614f1b3e8SDimitry Andric             "can't allocate 0x%" PRIx64
69714f1b3e8SDimitry Andric             " bytes for the memory read buffer, specify a smaller size to read",
69814f1b3e8SDimitry Andric             (uint64_t)((item_byte_size + 1) * item_count));
699b1c73532SDimitry Andric         return;
700f034231aSEd Maste       }
701f034231aSEd Maste       uint8_t *data_ptr = data_sp->GetBytes();
702f034231aSEd Maste       auto data_addr = addr;
703f034231aSEd Maste       auto count = item_count;
704f034231aSEd Maste       item_count = 0;
7055e95aa85SEd Maste       bool break_on_no_NULL = false;
70614f1b3e8SDimitry Andric       while (item_count < count) {
707f034231aSEd Maste         std::string buffer;
708f034231aSEd Maste         buffer.resize(item_byte_size + 1, 0);
709b76161e4SDimitry Andric         Status error;
71014f1b3e8SDimitry Andric         size_t read = target->ReadCStringFromMemory(data_addr, &buffer[0],
71114f1b3e8SDimitry Andric                                                     item_byte_size + 1, error);
71214f1b3e8SDimitry Andric         if (error.Fail()) {
71314f1b3e8SDimitry Andric           result.AppendErrorWithFormat(
71414f1b3e8SDimitry Andric               "failed to read memory from 0x%" PRIx64 ".\n", addr);
715b1c73532SDimitry Andric           return;
716f034231aSEd Maste         }
7175e95aa85SEd Maste 
71814f1b3e8SDimitry Andric         if (item_byte_size == read) {
71914f1b3e8SDimitry Andric           result.AppendWarningWithFormat(
72014f1b3e8SDimitry Andric               "unable to find a NULL terminated string at 0x%" PRIx64
72114f1b3e8SDimitry Andric               ". Consider increasing the maximum read length.\n",
72214f1b3e8SDimitry Andric               data_addr);
7235e95aa85SEd Maste           --read;
7245e95aa85SEd Maste           break_on_no_NULL = true;
72514f1b3e8SDimitry Andric         } else
7265e95aa85SEd Maste           ++read; // account for final NULL byte
7275e95aa85SEd Maste 
728f034231aSEd Maste         memcpy(data_ptr, &buffer[0], read);
729f034231aSEd Maste         data_ptr += read;
730f034231aSEd Maste         data_addr += read;
731f034231aSEd Maste         bytes_read += read;
73214f1b3e8SDimitry Andric         item_count++; // if we break early we know we only read item_count
73314f1b3e8SDimitry Andric                       // strings
7345e95aa85SEd Maste 
7355e95aa85SEd Maste         if (break_on_no_NULL)
7365e95aa85SEd Maste           break;
737f034231aSEd Maste       }
7385f29bb8aSDimitry Andric       data_sp =
7395f29bb8aSDimitry Andric           std::make_shared<DataBufferHeap>(data_sp->GetBytes(), bytes_read + 1);
740f034231aSEd Maste     }
741f034231aSEd Maste 
742f034231aSEd Maste     m_next_addr = addr + bytes_read;
743f034231aSEd Maste     m_prev_byte_size = bytes_read;
744f034231aSEd Maste     m_prev_format_options = m_format_options;
745f034231aSEd Maste     m_prev_memory_options = m_memory_options;
746f034231aSEd Maste     m_prev_outfile_options = m_outfile_options;
747f034231aSEd Maste     m_prev_varobj_options = m_varobj_options;
748145449b1SDimitry Andric     m_prev_memory_tag_options = m_memory_tag_options;
7495f29bb8aSDimitry Andric     m_prev_compiler_type = compiler_type;
750f034231aSEd Maste 
751ead24645SDimitry Andric     std::unique_ptr<Stream> output_stream_storage;
752ead24645SDimitry Andric     Stream *output_stream_p = nullptr;
75314f1b3e8SDimitry Andric     const FileSpec &outfile_spec =
75414f1b3e8SDimitry Andric         m_outfile_options.GetFile().GetCurrentValue();
75594994d37SDimitry Andric 
75694994d37SDimitry Andric     std::string path = outfile_spec.GetPath();
75714f1b3e8SDimitry Andric     if (outfile_spec) {
758f034231aSEd Maste 
759344a3780SDimitry Andric       File::OpenOptions open_options =
760c0981da4SDimitry Andric           File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate;
761f034231aSEd Maste       const bool append = m_outfile_options.GetAppend().GetCurrentValue();
762344a3780SDimitry Andric       open_options |=
763344a3780SDimitry Andric           append ? File::eOpenOptionAppend : File::eOpenOptionTruncate;
764f034231aSEd Maste 
765ead24645SDimitry Andric       auto outfile = FileSystem::Instance().Open(outfile_spec, open_options);
766ead24645SDimitry Andric 
767ead24645SDimitry Andric       if (outfile) {
768ead24645SDimitry Andric         auto outfile_stream_up =
769ead24645SDimitry Andric             std::make_unique<StreamFile>(std::move(outfile.get()));
77014f1b3e8SDimitry Andric         if (m_memory_options.m_output_as_binary) {
77114f1b3e8SDimitry Andric           const size_t bytes_written =
772ead24645SDimitry Andric               outfile_stream_up->Write(data_sp->GetBytes(), bytes_read);
77314f1b3e8SDimitry Andric           if (bytes_written > 0) {
77414f1b3e8SDimitry Andric             result.GetOutputStream().Printf(
77514f1b3e8SDimitry Andric                 "%zi bytes %s to '%s'\n", bytes_written,
77694994d37SDimitry Andric                 append ? "appended" : "written", path.c_str());
777b1c73532SDimitry Andric             return;
77814f1b3e8SDimitry Andric           } else {
77914f1b3e8SDimitry Andric             result.AppendErrorWithFormat("Failed to write %" PRIu64
78014f1b3e8SDimitry Andric                                          " bytes to '%s'.\n",
78194994d37SDimitry Andric                                          (uint64_t)bytes_read, path.c_str());
782b1c73532SDimitry Andric             return;
783f034231aSEd Maste           }
78414f1b3e8SDimitry Andric         } else {
785f034231aSEd Maste           // We are going to write ASCII to the file just point the
786f034231aSEd Maste           // output_stream to our outfile_stream...
787ead24645SDimitry Andric           output_stream_storage = std::move(outfile_stream_up);
788ead24645SDimitry Andric           output_stream_p = output_stream_storage.get();
789f034231aSEd Maste         }
79014f1b3e8SDimitry Andric       } else {
791ead24645SDimitry Andric         result.AppendErrorWithFormat("Failed to open file '%s' for %s:\n",
79294994d37SDimitry Andric                                      path.c_str(), append ? "append" : "write");
793ead24645SDimitry Andric 
794ead24645SDimitry Andric         result.AppendError(llvm::toString(outfile.takeError()));
795b1c73532SDimitry Andric         return;
796f034231aSEd Maste       }
79714f1b3e8SDimitry Andric     } else {
798ead24645SDimitry Andric       output_stream_p = &result.GetOutputStream();
799f034231aSEd Maste     }
800f034231aSEd Maste 
801f034231aSEd Maste     ExecutionContextScope *exe_scope = m_exe_ctx.GetBestExecutionContextScope();
8025f29bb8aSDimitry Andric     if (compiler_type.GetOpaqueQualType()) {
80314f1b3e8SDimitry Andric       for (uint32_t i = 0; i < item_count; ++i) {
804f034231aSEd Maste         addr_t item_addr = addr + (i * item_byte_size);
805f034231aSEd Maste         Address address(item_addr);
806f034231aSEd Maste         StreamString name_strm;
807f034231aSEd Maste         name_strm.Printf("0x%" PRIx64, item_addr);
80814f1b3e8SDimitry Andric         ValueObjectSP valobj_sp(ValueObjectMemory::Create(
8095f29bb8aSDimitry Andric             exe_scope, name_strm.GetString(), address, compiler_type));
81014f1b3e8SDimitry Andric         if (valobj_sp) {
811f034231aSEd Maste           Format format = m_format_options.GetFormat();
812f034231aSEd Maste           if (format != eFormatDefault)
813f034231aSEd Maste             valobj_sp->SetFormat(format);
814f034231aSEd Maste 
81514f1b3e8SDimitry Andric           DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
81614f1b3e8SDimitry Andric               eLanguageRuntimeDescriptionDisplayVerbosityFull, format));
817f034231aSEd Maste 
818ac9a064cSDimitry Andric           if (llvm::Error error = valobj_sp->Dump(*output_stream_p, options)) {
819ac9a064cSDimitry Andric             result.AppendError(toString(std::move(error)));
820ac9a064cSDimitry Andric             return;
821ac9a064cSDimitry Andric           }
82214f1b3e8SDimitry Andric         } else {
82314f1b3e8SDimitry Andric           result.AppendErrorWithFormat(
82414f1b3e8SDimitry Andric               "failed to create a value object for: (%s) %s\n",
82514f1b3e8SDimitry Andric               view_as_type_cstr, name_strm.GetData());
826b1c73532SDimitry Andric           return;
827f034231aSEd Maste         }
828f034231aSEd Maste       }
829b1c73532SDimitry Andric       return;
830f034231aSEd Maste     }
831f034231aSEd Maste 
832f034231aSEd Maste     result.SetStatus(eReturnStatusSuccessFinishResult);
83314f1b3e8SDimitry Andric     DataExtractor data(data_sp, target->GetArchitecture().GetByteOrder(),
834205afe67SEd Maste                        target->GetArchitecture().GetAddressByteSize(),
835205afe67SEd Maste                        target->GetArchitecture().GetDataByteSize());
836f034231aSEd Maste 
837f034231aSEd Maste     Format format = m_format_options.GetFormat();
83814f1b3e8SDimitry Andric     if (((format == eFormatChar) || (format == eFormatCharPrintable)) &&
83914f1b3e8SDimitry Andric         (item_byte_size != 1)) {
840f21a844fSEd Maste       // if a count was not passed, or it is 1
84114f1b3e8SDimitry Andric       if (!m_format_options.GetCountValue().OptionWasSet() || item_count == 1) {
842f034231aSEd Maste         // this turns requests such as
843f034231aSEd Maste         // memory read -fc -s10 -c1 *charPtrPtr
844f73363f1SDimitry Andric         // which make no sense (what is a char of size 10?) into a request for
845f73363f1SDimitry Andric         // fetching 10 chars of size 1 from the same memory location
846f034231aSEd Maste         format = eFormatCharArray;
847f034231aSEd Maste         item_count = item_byte_size;
848f034231aSEd Maste         item_byte_size = 1;
84914f1b3e8SDimitry Andric       } else {
850f73363f1SDimitry Andric         // here we passed a count, and it was not 1 so we have a byte_size and
851f73363f1SDimitry Andric         // a count we could well multiply those, but instead let's just fail
85214f1b3e8SDimitry Andric         result.AppendErrorWithFormat(
85314f1b3e8SDimitry Andric             "reading memory as characters of size %" PRIu64 " is not supported",
85414f1b3e8SDimitry Andric             (uint64_t)item_byte_size);
855b1c73532SDimitry Andric         return;
856f21a844fSEd Maste       }
857f21a844fSEd Maste     }
858f034231aSEd Maste 
859ead24645SDimitry Andric     assert(output_stream_p);
86074a628f7SDimitry Andric     size_t bytes_dumped = DumpDataExtractor(
861ead24645SDimitry Andric         data, output_stream_p, 0, format, item_byte_size, item_count,
86274a628f7SDimitry Andric         num_per_line / target->GetArchitecture().GetDataByteSize(), addr, 0, 0,
863145449b1SDimitry Andric         exe_scope, m_memory_tag_options.GetShowTags().GetCurrentValue());
864f034231aSEd Maste     m_next_addr = addr + bytes_dumped;
865ead24645SDimitry Andric     output_stream_p->EOL();
866f034231aSEd Maste   }
867f034231aSEd Maste 
868f034231aSEd Maste   OptionGroupOptions m_option_group;
869f034231aSEd Maste   OptionGroupFormat m_format_options;
870f034231aSEd Maste   OptionGroupReadMemory m_memory_options;
871f034231aSEd Maste   OptionGroupOutputFile m_outfile_options;
872f034231aSEd Maste   OptionGroupValueObjectDisplay m_varobj_options;
873145449b1SDimitry Andric   OptionGroupMemoryTag m_memory_tag_options;
874145449b1SDimitry Andric   lldb::addr_t m_next_addr = LLDB_INVALID_ADDRESS;
875145449b1SDimitry Andric   lldb::addr_t m_prev_byte_size = 0;
876f034231aSEd Maste   OptionGroupFormat m_prev_format_options;
877f034231aSEd Maste   OptionGroupReadMemory m_prev_memory_options;
878f034231aSEd Maste   OptionGroupOutputFile m_prev_outfile_options;
879f034231aSEd Maste   OptionGroupValueObjectDisplay m_prev_varobj_options;
880145449b1SDimitry Andric   OptionGroupMemoryTag m_prev_memory_tag_options;
8815f29bb8aSDimitry Andric   CompilerType m_prev_compiler_type;
882f034231aSEd Maste };
883f034231aSEd Maste 
884ead24645SDimitry Andric #define LLDB_OPTIONS_memory_find
885ead24645SDimitry Andric #include "CommandOptions.inc"
88686758c71SEd Maste 
88786758c71SEd Maste // Find the specified data in memory
88814f1b3e8SDimitry Andric class CommandObjectMemoryFind : public CommandObjectParsed {
88986758c71SEd Maste public:
89014f1b3e8SDimitry Andric   class OptionGroupFindMemory : public OptionGroup {
89186758c71SEd Maste   public:
OptionGroupFindMemory()8926f8fc217SDimitry Andric     OptionGroupFindMemory() : m_count(1), m_offset(0) {}
89386758c71SEd Maste 
894f3fbd1c0SDimitry Andric     ~OptionGroupFindMemory() override = default;
89586758c71SEd Maste 
GetDefinitions()89614f1b3e8SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
897e3b55780SDimitry Andric       return llvm::ArrayRef(g_memory_find_options);
89886758c71SEd Maste     }
89986758c71SEd Maste 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_value,ExecutionContext * execution_context)900b76161e4SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
90114f1b3e8SDimitry Andric                           ExecutionContext *execution_context) override {
902b76161e4SDimitry Andric       Status error;
903ead24645SDimitry Andric       const int short_option = g_memory_find_options[option_idx].short_option;
90486758c71SEd Maste 
90514f1b3e8SDimitry Andric       switch (short_option) {
90686758c71SEd Maste       case 'e':
90714f1b3e8SDimitry Andric         m_expr.SetValueFromString(option_value);
90886758c71SEd Maste         break;
90986758c71SEd Maste 
91086758c71SEd Maste       case 's':
91114f1b3e8SDimitry Andric         m_string.SetValueFromString(option_value);
91286758c71SEd Maste         break;
91386758c71SEd Maste 
91486758c71SEd Maste       case 'c':
91514f1b3e8SDimitry Andric         if (m_count.SetValueFromString(option_value).Fail())
91686758c71SEd Maste           error.SetErrorString("unrecognized value for count");
91786758c71SEd Maste         break;
91886758c71SEd Maste 
91986758c71SEd Maste       case 'o':
92014f1b3e8SDimitry Andric         if (m_offset.SetValueFromString(option_value).Fail())
92186758c71SEd Maste           error.SetErrorString("unrecognized value for dump-offset");
92286758c71SEd Maste         break;
92386758c71SEd Maste 
92486758c71SEd Maste       default:
925ead24645SDimitry Andric         llvm_unreachable("Unimplemented option");
92686758c71SEd Maste       }
92786758c71SEd Maste       return error;
92886758c71SEd Maste     }
92986758c71SEd Maste 
OptionParsingStarting(ExecutionContext * execution_context)93014f1b3e8SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
93186758c71SEd Maste       m_expr.Clear();
93286758c71SEd Maste       m_string.Clear();
93386758c71SEd Maste       m_count.Clear();
93486758c71SEd Maste     }
93586758c71SEd Maste 
93686758c71SEd Maste     OptionValueString m_expr;
93786758c71SEd Maste     OptionValueString m_string;
93886758c71SEd Maste     OptionValueUInt64 m_count;
93986758c71SEd Maste     OptionValueUInt64 m_offset;
94086758c71SEd Maste   };
94186758c71SEd Maste 
CommandObjectMemoryFind(CommandInterpreter & interpreter)942f3fbd1c0SDimitry Andric   CommandObjectMemoryFind(CommandInterpreter &interpreter)
94314f1b3e8SDimitry Andric       : CommandObjectParsed(
94414f1b3e8SDimitry Andric             interpreter, "memory find",
94514f1b3e8SDimitry Andric             "Find a value in the memory of the current target process.",
9466f8fc217SDimitry Andric             nullptr, eCommandRequiresProcess | eCommandProcessMustBeLaunched) {
94786758c71SEd Maste     CommandArgumentEntry arg1;
94886758c71SEd Maste     CommandArgumentEntry arg2;
94986758c71SEd Maste     CommandArgumentData addr_arg;
95086758c71SEd Maste     CommandArgumentData value_arg;
95186758c71SEd Maste 
95286758c71SEd Maste     // Define the first (and only) variant of this arg.
953e81d9d49SDimitry Andric     addr_arg.arg_type = eArgTypeAddressOrExpression;
95486758c71SEd Maste     addr_arg.arg_repetition = eArgRepeatPlain;
95586758c71SEd Maste 
95614f1b3e8SDimitry Andric     // There is only one variant this argument could be; put it into the
95714f1b3e8SDimitry Andric     // argument entry.
95886758c71SEd Maste     arg1.push_back(addr_arg);
95986758c71SEd Maste 
96086758c71SEd Maste     // Define the first (and only) variant of this arg.
961e81d9d49SDimitry Andric     value_arg.arg_type = eArgTypeAddressOrExpression;
962e81d9d49SDimitry Andric     value_arg.arg_repetition = eArgRepeatPlain;
96386758c71SEd Maste 
96414f1b3e8SDimitry Andric     // There is only one variant this argument could be; put it into the
96514f1b3e8SDimitry Andric     // argument entry.
96686758c71SEd Maste     arg2.push_back(value_arg);
96786758c71SEd Maste 
96886758c71SEd Maste     // Push the data for the first argument into the m_arguments vector.
96986758c71SEd Maste     m_arguments.push_back(arg1);
97086758c71SEd Maste     m_arguments.push_back(arg2);
97186758c71SEd Maste 
972f3fbd1c0SDimitry Andric     m_option_group.Append(&m_memory_options);
973145449b1SDimitry Andric     m_option_group.Append(&m_memory_tag_options, LLDB_OPT_SET_ALL,
974145449b1SDimitry Andric                           LLDB_OPT_SET_ALL);
97586758c71SEd Maste     m_option_group.Finalize();
97686758c71SEd Maste   }
97786758c71SEd Maste 
978f3fbd1c0SDimitry Andric   ~CommandObjectMemoryFind() override = default;
97986758c71SEd Maste 
GetOptions()98014f1b3e8SDimitry Andric   Options *GetOptions() override { return &m_option_group; }
98186758c71SEd Maste 
98286758c71SEd Maste protected:
DoExecute(Args & command,CommandReturnObject & result)983b1c73532SDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
98414f1b3e8SDimitry Andric     // No need to check "process" for validity as eCommandRequiresProcess
98514f1b3e8SDimitry Andric     // ensures it is valid
98686758c71SEd Maste     Process *process = m_exe_ctx.GetProcessPtr();
98786758c71SEd Maste 
98886758c71SEd Maste     const size_t argc = command.GetArgumentCount();
98986758c71SEd Maste 
99014f1b3e8SDimitry Andric     if (argc != 2) {
99186758c71SEd Maste       result.AppendError("two addresses needed for memory find");
992b1c73532SDimitry Andric       return;
99386758c71SEd Maste     }
99486758c71SEd Maste 
995b76161e4SDimitry Andric     Status error;
996f73363f1SDimitry Andric     lldb::addr_t low_addr = OptionArgParser::ToAddress(
997ead24645SDimitry Andric         &m_exe_ctx, command[0].ref(), LLDB_INVALID_ADDRESS, &error);
99814f1b3e8SDimitry Andric     if (low_addr == LLDB_INVALID_ADDRESS || error.Fail()) {
99986758c71SEd Maste       result.AppendError("invalid low address");
1000b1c73532SDimitry Andric       return;
100186758c71SEd Maste     }
1002f73363f1SDimitry Andric     lldb::addr_t high_addr = OptionArgParser::ToAddress(
1003ead24645SDimitry Andric         &m_exe_ctx, command[1].ref(), LLDB_INVALID_ADDRESS, &error);
100414f1b3e8SDimitry Andric     if (high_addr == LLDB_INVALID_ADDRESS || error.Fail()) {
1005205afe67SEd Maste       result.AppendError("invalid high address");
1006b1c73532SDimitry Andric       return;
100786758c71SEd Maste     }
100886758c71SEd Maste 
100914f1b3e8SDimitry Andric     if (high_addr <= low_addr) {
101014f1b3e8SDimitry Andric       result.AppendError(
101114f1b3e8SDimitry Andric           "starting address must be smaller than ending address");
1012b1c73532SDimitry Andric       return;
101386758c71SEd Maste     }
101486758c71SEd Maste 
101586758c71SEd Maste     lldb::addr_t found_location = LLDB_INVALID_ADDRESS;
101686758c71SEd Maste 
101786758c71SEd Maste     DataBufferHeap buffer;
101886758c71SEd Maste 
1019145449b1SDimitry Andric     if (m_memory_options.m_string.OptionWasSet()) {
10207fa27ce4SDimitry Andric       llvm::StringRef str =
10217fa27ce4SDimitry Andric           m_memory_options.m_string.GetValueAs<llvm::StringRef>().value_or("");
1022145449b1SDimitry Andric       if (str.empty()) {
1023145449b1SDimitry Andric         result.AppendError("search string must have non-zero length.");
1024b1c73532SDimitry Andric         return;
1025145449b1SDimitry Andric       }
1026145449b1SDimitry Andric       buffer.CopyData(str);
1027145449b1SDimitry Andric     } else if (m_memory_options.m_expr.OptionWasSet()) {
102886758c71SEd Maste       StackFrame *frame = m_exe_ctx.GetFramePtr();
102986758c71SEd Maste       ValueObjectSP result_sp;
103014f1b3e8SDimitry Andric       if ((eExpressionCompleted ==
103114f1b3e8SDimitry Andric            process->GetTarget().EvaluateExpression(
10327fa27ce4SDimitry Andric                m_memory_options.m_expr.GetValueAs<llvm::StringRef>().value_or(
10337fa27ce4SDimitry Andric                    ""),
10347fa27ce4SDimitry Andric                frame, result_sp)) &&
103514f1b3e8SDimitry Andric           result_sp) {
103686758c71SEd Maste         uint64_t value = result_sp->GetValueAsUnsigned(0);
1037e3b55780SDimitry Andric         std::optional<uint64_t> size =
103894994d37SDimitry Andric             result_sp->GetCompilerType().GetByteSize(nullptr);
103994994d37SDimitry Andric         if (!size)
1040b1c73532SDimitry Andric           return;
104194994d37SDimitry Andric         switch (*size) {
104286758c71SEd Maste         case 1: {
104386758c71SEd Maste           uint8_t byte = (uint8_t)value;
104486758c71SEd Maste           buffer.CopyData(&byte, 1);
104514f1b3e8SDimitry Andric         } break;
104686758c71SEd Maste         case 2: {
104786758c71SEd Maste           uint16_t word = (uint16_t)value;
104886758c71SEd Maste           buffer.CopyData(&word, 2);
104914f1b3e8SDimitry Andric         } break;
105086758c71SEd Maste         case 4: {
105186758c71SEd Maste           uint32_t lword = (uint32_t)value;
105286758c71SEd Maste           buffer.CopyData(&lword, 4);
105314f1b3e8SDimitry Andric         } break;
105486758c71SEd Maste         case 8: {
105586758c71SEd Maste           buffer.CopyData(&value, 8);
105614f1b3e8SDimitry Andric         } break;
105786758c71SEd Maste         case 3:
105886758c71SEd Maste         case 5:
105986758c71SEd Maste         case 6:
106086758c71SEd Maste         case 7:
106186758c71SEd Maste           result.AppendError("unknown type. pass a string instead");
1062b1c73532SDimitry Andric           return;
106386758c71SEd Maste         default:
106414f1b3e8SDimitry Andric           result.AppendError(
106514f1b3e8SDimitry Andric               "result size larger than 8 bytes. pass a string instead");
1066b1c73532SDimitry Andric           return;
106786758c71SEd Maste         }
106814f1b3e8SDimitry Andric       } else {
106914f1b3e8SDimitry Andric         result.AppendError(
107014f1b3e8SDimitry Andric             "expression evaluation failed. pass a string instead");
1071b1c73532SDimitry Andric         return;
107286758c71SEd Maste       }
107314f1b3e8SDimitry Andric     } else {
107414f1b3e8SDimitry Andric       result.AppendError(
107514f1b3e8SDimitry Andric           "please pass either a block of text, or an expression to evaluate.");
1076b1c73532SDimitry Andric       return;
107786758c71SEd Maste     }
107886758c71SEd Maste 
107986758c71SEd Maste     size_t count = m_memory_options.m_count.GetCurrentValue();
108086758c71SEd Maste     found_location = low_addr;
108186758c71SEd Maste     bool ever_found = false;
108214f1b3e8SDimitry Andric     while (count) {
1083ac9a064cSDimitry Andric       found_location = process->FindInMemory(
1084ac9a064cSDimitry Andric           found_location, high_addr, buffer.GetBytes(), buffer.GetByteSize());
108514f1b3e8SDimitry Andric       if (found_location == LLDB_INVALID_ADDRESS) {
108614f1b3e8SDimitry Andric         if (!ever_found) {
1087e81d9d49SDimitry Andric           result.AppendMessage("data not found within the range.\n");
108886758c71SEd Maste           result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
108914f1b3e8SDimitry Andric         } else
1090e81d9d49SDimitry Andric           result.AppendMessage("no more matches within the range.\n");
109186758c71SEd Maste         break;
109286758c71SEd Maste       }
109314f1b3e8SDimitry Andric       result.AppendMessageWithFormat("data found at location: 0x%" PRIx64 "\n",
109414f1b3e8SDimitry Andric                                      found_location);
109586758c71SEd Maste 
109686758c71SEd Maste       DataBufferHeap dumpbuffer(32, 0);
109714f1b3e8SDimitry Andric       process->ReadMemory(
109814f1b3e8SDimitry Andric           found_location + m_memory_options.m_offset.GetCurrentValue(),
109914f1b3e8SDimitry Andric           dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(), error);
110014f1b3e8SDimitry Andric       if (!error.Fail()) {
110114f1b3e8SDimitry Andric         DataExtractor data(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(),
110214f1b3e8SDimitry Andric                            process->GetByteOrder(),
110314f1b3e8SDimitry Andric                            process->GetAddressByteSize());
110474a628f7SDimitry Andric         DumpDataExtractor(
110574a628f7SDimitry Andric             data, &result.GetOutputStream(), 0, lldb::eFormatBytesWithASCII, 1,
110614f1b3e8SDimitry Andric             dumpbuffer.GetByteSize(), 16,
1107145449b1SDimitry Andric             found_location + m_memory_options.m_offset.GetCurrentValue(), 0, 0,
1108145449b1SDimitry Andric             m_exe_ctx.GetBestExecutionContextScope(),
1109145449b1SDimitry Andric             m_memory_tag_options.GetShowTags().GetCurrentValue());
111086758c71SEd Maste         result.GetOutputStream().EOL();
111186758c71SEd Maste       }
111286758c71SEd Maste 
111386758c71SEd Maste       --count;
111486758c71SEd Maste       found_location++;
111586758c71SEd Maste       ever_found = true;
111686758c71SEd Maste     }
111786758c71SEd Maste 
111886758c71SEd Maste     result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
111986758c71SEd Maste   }
112086758c71SEd Maste 
112186758c71SEd Maste   OptionGroupOptions m_option_group;
112286758c71SEd Maste   OptionGroupFindMemory m_memory_options;
1123145449b1SDimitry Andric   OptionGroupMemoryTag m_memory_tag_options;
112486758c71SEd Maste };
112586758c71SEd Maste 
1126ead24645SDimitry Andric #define LLDB_OPTIONS_memory_write
1127ead24645SDimitry Andric #include "CommandOptions.inc"
1128f034231aSEd Maste 
1129f034231aSEd Maste // Write memory to the inferior process
113014f1b3e8SDimitry Andric class CommandObjectMemoryWrite : public CommandObjectParsed {
1131f034231aSEd Maste public:
113214f1b3e8SDimitry Andric   class OptionGroupWriteMemory : public OptionGroup {
1133f034231aSEd Maste   public:
1134145449b1SDimitry Andric     OptionGroupWriteMemory() = default;
1135f034231aSEd Maste 
1136f3fbd1c0SDimitry Andric     ~OptionGroupWriteMemory() override = default;
1137f034231aSEd Maste 
GetDefinitions()113814f1b3e8SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1139e3b55780SDimitry Andric       return llvm::ArrayRef(g_memory_write_options);
1140f034231aSEd Maste     }
1141f034231aSEd Maste 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_value,ExecutionContext * execution_context)1142b76161e4SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
114314f1b3e8SDimitry Andric                           ExecutionContext *execution_context) override {
1144b76161e4SDimitry Andric       Status error;
1145ead24645SDimitry Andric       const int short_option = g_memory_write_options[option_idx].short_option;
1146f034231aSEd Maste 
114714f1b3e8SDimitry Andric       switch (short_option) {
1148f034231aSEd Maste       case 'i':
114994994d37SDimitry Andric         m_infile.SetFile(option_value, FileSpec::Style::native);
115094994d37SDimitry Andric         FileSystem::Instance().Resolve(m_infile);
115194994d37SDimitry Andric         if (!FileSystem::Instance().Exists(m_infile)) {
1152f034231aSEd Maste           m_infile.Clear();
115314f1b3e8SDimitry Andric           error.SetErrorStringWithFormat("input file does not exist: '%s'",
115414f1b3e8SDimitry Andric                                          option_value.str().c_str());
1155f034231aSEd Maste         }
1156f034231aSEd Maste         break;
1157f034231aSEd Maste 
115814f1b3e8SDimitry Andric       case 'o': {
115914f1b3e8SDimitry Andric         if (option_value.getAsInteger(0, m_infile_offset)) {
116014f1b3e8SDimitry Andric           m_infile_offset = 0;
116114f1b3e8SDimitry Andric           error.SetErrorStringWithFormat("invalid offset string '%s'",
116214f1b3e8SDimitry Andric                                          option_value.str().c_str());
1163f034231aSEd Maste         }
116414f1b3e8SDimitry Andric       } break;
1165f034231aSEd Maste 
1166f034231aSEd Maste       default:
1167ead24645SDimitry Andric         llvm_unreachable("Unimplemented option");
1168f034231aSEd Maste       }
1169f034231aSEd Maste       return error;
1170f034231aSEd Maste     }
1171f034231aSEd Maste 
OptionParsingStarting(ExecutionContext * execution_context)117214f1b3e8SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
1173f034231aSEd Maste       m_infile.Clear();
1174f034231aSEd Maste       m_infile_offset = 0;
1175f034231aSEd Maste     }
1176f034231aSEd Maste 
1177f034231aSEd Maste     FileSpec m_infile;
1178f034231aSEd Maste     off_t m_infile_offset;
1179f034231aSEd Maste   };
1180f034231aSEd Maste 
CommandObjectMemoryWrite(CommandInterpreter & interpreter)1181f3fbd1c0SDimitry Andric   CommandObjectMemoryWrite(CommandInterpreter &interpreter)
118214f1b3e8SDimitry Andric       : CommandObjectParsed(
118314f1b3e8SDimitry Andric             interpreter, "memory write",
118414f1b3e8SDimitry Andric             "Write to the memory of the current target process.", nullptr,
118514f1b3e8SDimitry Andric             eCommandRequiresProcess | eCommandProcessMustBeLaunched),
1186f65dcba8SDimitry Andric         m_format_options(
1187f65dcba8SDimitry Andric             eFormatBytes, 1, UINT64_MAX,
1188f65dcba8SDimitry Andric             {std::make_tuple(
1189f65dcba8SDimitry Andric                  eArgTypeFormat,
1190f65dcba8SDimitry Andric                  "The format to use for each of the value to be written."),
11916f8fc217SDimitry Andric              std::make_tuple(eArgTypeByteSize,
11926f8fc217SDimitry Andric                              "The size in bytes to write from input file or "
11936f8fc217SDimitry Andric                              "each value.")}) {
1194f034231aSEd Maste     CommandArgumentEntry arg1;
1195f034231aSEd Maste     CommandArgumentEntry arg2;
1196f034231aSEd Maste     CommandArgumentData addr_arg;
1197f034231aSEd Maste     CommandArgumentData value_arg;
1198f034231aSEd Maste 
1199f034231aSEd Maste     // Define the first (and only) variant of this arg.
1200f034231aSEd Maste     addr_arg.arg_type = eArgTypeAddress;
1201f034231aSEd Maste     addr_arg.arg_repetition = eArgRepeatPlain;
1202f034231aSEd Maste 
120314f1b3e8SDimitry Andric     // There is only one variant this argument could be; put it into the
120414f1b3e8SDimitry Andric     // argument entry.
1205f034231aSEd Maste     arg1.push_back(addr_arg);
1206f034231aSEd Maste 
1207f034231aSEd Maste     // Define the first (and only) variant of this arg.
1208f034231aSEd Maste     value_arg.arg_type = eArgTypeValue;
1209f034231aSEd Maste     value_arg.arg_repetition = eArgRepeatPlus;
1210f65dcba8SDimitry Andric     value_arg.arg_opt_set_association = LLDB_OPT_SET_1;
1211f034231aSEd Maste 
121214f1b3e8SDimitry Andric     // There is only one variant this argument could be; put it into the
121314f1b3e8SDimitry Andric     // argument entry.
1214f034231aSEd Maste     arg2.push_back(value_arg);
1215f034231aSEd Maste 
1216f034231aSEd Maste     // Push the data for the first argument into the m_arguments vector.
1217f034231aSEd Maste     m_arguments.push_back(arg1);
1218f034231aSEd Maste     m_arguments.push_back(arg2);
1219f034231aSEd Maste 
122014f1b3e8SDimitry Andric     m_option_group.Append(&m_format_options,
122114f1b3e8SDimitry Andric                           OptionGroupFormat::OPTION_GROUP_FORMAT,
122214f1b3e8SDimitry Andric                           LLDB_OPT_SET_1);
122314f1b3e8SDimitry Andric     m_option_group.Append(&m_format_options,
122414f1b3e8SDimitry Andric                           OptionGroupFormat::OPTION_GROUP_SIZE,
122514f1b3e8SDimitry Andric                           LLDB_OPT_SET_1 | LLDB_OPT_SET_2);
1226f034231aSEd Maste     m_option_group.Append(&m_memory_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_2);
1227f034231aSEd Maste     m_option_group.Finalize();
1228f034231aSEd Maste   }
1229f034231aSEd Maste 
1230f3fbd1c0SDimitry Andric   ~CommandObjectMemoryWrite() override = default;
1231f034231aSEd Maste 
GetOptions()123214f1b3e8SDimitry Andric   Options *GetOptions() override { return &m_option_group; }
1233f034231aSEd Maste 
1234f034231aSEd Maste protected:
DoExecute(Args & command,CommandReturnObject & result)1235b1c73532SDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
123614f1b3e8SDimitry Andric     // No need to check "process" for validity as eCommandRequiresProcess
123714f1b3e8SDimitry Andric     // ensures it is valid
1238f034231aSEd Maste     Process *process = m_exe_ctx.GetProcessPtr();
1239f034231aSEd Maste 
1240f034231aSEd Maste     const size_t argc = command.GetArgumentCount();
1241f034231aSEd Maste 
124214f1b3e8SDimitry Andric     if (m_memory_options.m_infile) {
124314f1b3e8SDimitry Andric       if (argc < 1) {
124414f1b3e8SDimitry Andric         result.AppendErrorWithFormat(
124514f1b3e8SDimitry Andric             "%s takes a destination address when writing file contents.\n",
124614f1b3e8SDimitry Andric             m_cmd_name.c_str());
1247b1c73532SDimitry Andric         return;
1248f034231aSEd Maste       }
1249f65dcba8SDimitry Andric       if (argc > 1) {
1250f65dcba8SDimitry Andric         result.AppendErrorWithFormat(
1251f65dcba8SDimitry Andric             "%s takes only a destination address when writing file contents.\n",
1252f65dcba8SDimitry Andric             m_cmd_name.c_str());
1253b1c73532SDimitry Andric         return;
1254f65dcba8SDimitry Andric       }
125514f1b3e8SDimitry Andric     } else if (argc < 2) {
125614f1b3e8SDimitry Andric       result.AppendErrorWithFormat(
125714f1b3e8SDimitry Andric           "%s takes a destination address and at least one value.\n",
125814f1b3e8SDimitry Andric           m_cmd_name.c_str());
1259b1c73532SDimitry Andric       return;
1260f034231aSEd Maste     }
1261f034231aSEd Maste 
126214f1b3e8SDimitry Andric     StreamString buffer(
126314f1b3e8SDimitry Andric         Stream::eBinary,
1264f034231aSEd Maste         process->GetTarget().GetArchitecture().GetAddressByteSize(),
1265f034231aSEd Maste         process->GetTarget().GetArchitecture().GetByteOrder());
1266f034231aSEd Maste 
1267f034231aSEd Maste     OptionValueUInt64 &byte_size_value = m_format_options.GetByteSizeValue();
1268f034231aSEd Maste     size_t item_byte_size = byte_size_value.GetCurrentValue();
1269f034231aSEd Maste 
1270b76161e4SDimitry Andric     Status error;
1271f73363f1SDimitry Andric     lldb::addr_t addr = OptionArgParser::ToAddress(
1272ead24645SDimitry Andric         &m_exe_ctx, command[0].ref(), LLDB_INVALID_ADDRESS, &error);
1273f034231aSEd Maste 
127414f1b3e8SDimitry Andric     if (addr == LLDB_INVALID_ADDRESS) {
1275f034231aSEd Maste       result.AppendError("invalid address expression\n");
1276f034231aSEd Maste       result.AppendError(error.AsCString());
1277b1c73532SDimitry Andric       return;
1278f034231aSEd Maste     }
1279f034231aSEd Maste 
128014f1b3e8SDimitry Andric     if (m_memory_options.m_infile) {
1281f034231aSEd Maste       size_t length = SIZE_MAX;
128212bd4897SEd Maste       if (item_byte_size > 1)
1283f034231aSEd Maste         length = item_byte_size;
128494994d37SDimitry Andric       auto data_sp = FileSystem::Instance().CreateDataBuffer(
128574a628f7SDimitry Andric           m_memory_options.m_infile.GetPath(), length,
128674a628f7SDimitry Andric           m_memory_options.m_infile_offset);
128714f1b3e8SDimitry Andric       if (data_sp) {
1288f034231aSEd Maste         length = data_sp->GetByteSize();
128914f1b3e8SDimitry Andric         if (length > 0) {
1290b76161e4SDimitry Andric           Status error;
129114f1b3e8SDimitry Andric           size_t bytes_written =
129214f1b3e8SDimitry Andric               process->WriteMemory(addr, data_sp->GetBytes(), length, error);
1293f034231aSEd Maste 
129414f1b3e8SDimitry Andric           if (bytes_written == length) {
1295f034231aSEd Maste             // All bytes written
129614f1b3e8SDimitry Andric             result.GetOutputStream().Printf(
129714f1b3e8SDimitry Andric                 "%" PRIu64 " bytes were written to 0x%" PRIx64 "\n",
129814f1b3e8SDimitry Andric                 (uint64_t)bytes_written, addr);
1299f034231aSEd Maste             result.SetStatus(eReturnStatusSuccessFinishResult);
130014f1b3e8SDimitry Andric           } else if (bytes_written > 0) {
1301f034231aSEd Maste             // Some byte written
130214f1b3e8SDimitry Andric             result.GetOutputStream().Printf(
130314f1b3e8SDimitry Andric                 "%" PRIu64 " bytes of %" PRIu64
130414f1b3e8SDimitry Andric                 " requested were written to 0x%" PRIx64 "\n",
130514f1b3e8SDimitry Andric                 (uint64_t)bytes_written, (uint64_t)length, addr);
1306f034231aSEd Maste             result.SetStatus(eReturnStatusSuccessFinishResult);
130714f1b3e8SDimitry Andric           } else {
130814f1b3e8SDimitry Andric             result.AppendErrorWithFormat("Memory write to 0x%" PRIx64
130914f1b3e8SDimitry Andric                                          " failed: %s.\n",
131014f1b3e8SDimitry Andric                                          addr, error.AsCString());
1311f034231aSEd Maste           }
1312f034231aSEd Maste         }
131314f1b3e8SDimitry Andric       } else {
1314f034231aSEd Maste         result.AppendErrorWithFormat("Unable to read contents of file.\n");
1315f034231aSEd Maste       }
1316b1c73532SDimitry Andric       return;
131714f1b3e8SDimitry Andric     } else if (item_byte_size == 0) {
1318f034231aSEd Maste       if (m_format_options.GetFormat() == eFormatPointer)
1319f034231aSEd Maste         item_byte_size = buffer.GetAddressByteSize();
1320f034231aSEd Maste       else
1321f034231aSEd Maste         item_byte_size = 1;
1322f034231aSEd Maste     }
1323f034231aSEd Maste 
1324f034231aSEd Maste     command.Shift(); // shift off the address argument
1325f034231aSEd Maste     uint64_t uval64;
1326f034231aSEd Maste     int64_t sval64;
1327f034231aSEd Maste     bool success = false;
132814f1b3e8SDimitry Andric     for (auto &entry : command) {
132914f1b3e8SDimitry Andric       switch (m_format_options.GetFormat()) {
1330f034231aSEd Maste       case kNumFormats:
1331f034231aSEd Maste       case eFormatFloat: // TODO: add support for floats soon
1332f034231aSEd Maste       case eFormatCharPrintable:
1333f034231aSEd Maste       case eFormatBytesWithASCII:
1334f034231aSEd Maste       case eFormatComplex:
1335f034231aSEd Maste       case eFormatEnum:
1336ead24645SDimitry Andric       case eFormatUnicode8:
1337f034231aSEd Maste       case eFormatUnicode16:
1338f034231aSEd Maste       case eFormatUnicode32:
1339f034231aSEd Maste       case eFormatVectorOfChar:
1340f034231aSEd Maste       case eFormatVectorOfSInt8:
1341f034231aSEd Maste       case eFormatVectorOfUInt8:
1342f034231aSEd Maste       case eFormatVectorOfSInt16:
1343f034231aSEd Maste       case eFormatVectorOfUInt16:
1344f034231aSEd Maste       case eFormatVectorOfSInt32:
1345f034231aSEd Maste       case eFormatVectorOfUInt32:
1346f034231aSEd Maste       case eFormatVectorOfSInt64:
1347f034231aSEd Maste       case eFormatVectorOfUInt64:
1348e81d9d49SDimitry Andric       case eFormatVectorOfFloat16:
1349f034231aSEd Maste       case eFormatVectorOfFloat32:
1350f034231aSEd Maste       case eFormatVectorOfFloat64:
1351f034231aSEd Maste       case eFormatVectorOfUInt128:
1352f034231aSEd Maste       case eFormatOSType:
1353f034231aSEd Maste       case eFormatComplexInteger:
1354f034231aSEd Maste       case eFormatAddressInfo:
1355f034231aSEd Maste       case eFormatHexFloat:
1356f034231aSEd Maste       case eFormatInstruction:
1357f034231aSEd Maste       case eFormatVoid:
1358f034231aSEd Maste         result.AppendError("unsupported format for writing memory");
1359b1c73532SDimitry Andric         return;
1360f034231aSEd Maste 
1361f034231aSEd Maste       case eFormatDefault:
1362f034231aSEd Maste       case eFormatBytes:
1363f034231aSEd Maste       case eFormatHex:
1364f034231aSEd Maste       case eFormatHexUppercase:
1365706b4fc4SDimitry Andric       case eFormatPointer: {
1366f034231aSEd Maste         // Decode hex bytes
136774a628f7SDimitry Andric         // Be careful, getAsInteger with a radix of 16 rejects "0xab" so we
136874a628f7SDimitry Andric         // have to special case that:
136974a628f7SDimitry Andric         bool success = false;
1370312c0ed1SDimitry Andric         if (entry.ref().starts_with("0x"))
1371ead24645SDimitry Andric           success = !entry.ref().getAsInteger(0, uval64);
137274a628f7SDimitry Andric         if (!success)
1373ead24645SDimitry Andric           success = !entry.ref().getAsInteger(16, uval64);
137474a628f7SDimitry Andric         if (!success) {
137514f1b3e8SDimitry Andric           result.AppendErrorWithFormat(
137614f1b3e8SDimitry Andric               "'%s' is not a valid hex string value.\n", entry.c_str());
1377b1c73532SDimitry Andric           return;
1378b60736ecSDimitry Andric         } else if (!llvm::isUIntN(item_byte_size * 8, uval64)) {
137914f1b3e8SDimitry Andric           result.AppendErrorWithFormat("Value 0x%" PRIx64
138014f1b3e8SDimitry Andric                                        " is too large to fit in a %" PRIu64
138114f1b3e8SDimitry Andric                                        " byte unsigned integer value.\n",
138214f1b3e8SDimitry Andric                                        uval64, (uint64_t)item_byte_size);
1383b1c73532SDimitry Andric           return;
1384f034231aSEd Maste         }
1385f034231aSEd Maste         buffer.PutMaxHex64(uval64, item_byte_size);
1386f034231aSEd Maste         break;
138774a628f7SDimitry Andric       }
1388f034231aSEd Maste       case eFormatBoolean:
1389ead24645SDimitry Andric         uval64 = OptionArgParser::ToBoolean(entry.ref(), false, &success);
139014f1b3e8SDimitry Andric         if (!success) {
139114f1b3e8SDimitry Andric           result.AppendErrorWithFormat(
139214f1b3e8SDimitry Andric               "'%s' is not a valid boolean string value.\n", entry.c_str());
1393b1c73532SDimitry Andric           return;
1394f034231aSEd Maste         }
1395f034231aSEd Maste         buffer.PutMaxHex64(uval64, item_byte_size);
1396f034231aSEd Maste         break;
1397f034231aSEd Maste 
1398f034231aSEd Maste       case eFormatBinary:
1399ead24645SDimitry Andric         if (entry.ref().getAsInteger(2, uval64)) {
140014f1b3e8SDimitry Andric           result.AppendErrorWithFormat(
140114f1b3e8SDimitry Andric               "'%s' is not a valid binary string value.\n", entry.c_str());
1402b1c73532SDimitry Andric           return;
1403b60736ecSDimitry Andric         } else if (!llvm::isUIntN(item_byte_size * 8, uval64)) {
140414f1b3e8SDimitry Andric           result.AppendErrorWithFormat("Value 0x%" PRIx64
140514f1b3e8SDimitry Andric                                        " is too large to fit in a %" PRIu64
140614f1b3e8SDimitry Andric                                        " byte unsigned integer value.\n",
140714f1b3e8SDimitry Andric                                        uval64, (uint64_t)item_byte_size);
1408b1c73532SDimitry Andric           return;
1409f034231aSEd Maste         }
1410f034231aSEd Maste         buffer.PutMaxHex64(uval64, item_byte_size);
1411f034231aSEd Maste         break;
1412f034231aSEd Maste 
1413f034231aSEd Maste       case eFormatCharArray:
1414f034231aSEd Maste       case eFormatChar:
141514f1b3e8SDimitry Andric       case eFormatCString: {
1416ead24645SDimitry Andric         if (entry.ref().empty())
141714f1b3e8SDimitry Andric           break;
141814f1b3e8SDimitry Andric 
1419ead24645SDimitry Andric         size_t len = entry.ref().size();
1420f034231aSEd Maste         // Include the NULL for C strings...
1421f034231aSEd Maste         if (m_format_options.GetFormat() == eFormatCString)
1422f034231aSEd Maste           ++len;
1423b76161e4SDimitry Andric         Status error;
142414f1b3e8SDimitry Andric         if (process->WriteMemory(addr, entry.c_str(), len, error) == len) {
1425f034231aSEd Maste           addr += len;
142614f1b3e8SDimitry Andric         } else {
142714f1b3e8SDimitry Andric           result.AppendErrorWithFormat("Memory write to 0x%" PRIx64
142814f1b3e8SDimitry Andric                                        " failed: %s.\n",
142914f1b3e8SDimitry Andric                                        addr, error.AsCString());
1430b1c73532SDimitry Andric           return;
1431f034231aSEd Maste         }
1432f034231aSEd Maste         break;
143314f1b3e8SDimitry Andric       }
1434f034231aSEd Maste       case eFormatDecimal:
1435ead24645SDimitry Andric         if (entry.ref().getAsInteger(0, sval64)) {
143614f1b3e8SDimitry Andric           result.AppendErrorWithFormat(
143714f1b3e8SDimitry Andric               "'%s' is not a valid signed decimal value.\n", entry.c_str());
1438b1c73532SDimitry Andric           return;
1439b60736ecSDimitry Andric         } else if (!llvm::isIntN(item_byte_size * 8, sval64)) {
144014f1b3e8SDimitry Andric           result.AppendErrorWithFormat(
144114f1b3e8SDimitry Andric               "Value %" PRIi64 " is too large or small to fit in a %" PRIu64
144214f1b3e8SDimitry Andric               " byte signed integer value.\n",
144314f1b3e8SDimitry Andric               sval64, (uint64_t)item_byte_size);
1444b1c73532SDimitry Andric           return;
1445f034231aSEd Maste         }
1446f034231aSEd Maste         buffer.PutMaxHex64(sval64, item_byte_size);
1447f034231aSEd Maste         break;
1448f034231aSEd Maste 
1449f034231aSEd Maste       case eFormatUnsigned:
145014f1b3e8SDimitry Andric 
1451344a3780SDimitry Andric         if (entry.ref().getAsInteger(0, uval64)) {
145214f1b3e8SDimitry Andric           result.AppendErrorWithFormat(
145314f1b3e8SDimitry Andric               "'%s' is not a valid unsigned decimal string value.\n",
145414f1b3e8SDimitry Andric               entry.c_str());
1455b1c73532SDimitry Andric           return;
1456b60736ecSDimitry Andric         } else if (!llvm::isUIntN(item_byte_size * 8, uval64)) {
145714f1b3e8SDimitry Andric           result.AppendErrorWithFormat("Value %" PRIu64
145814f1b3e8SDimitry Andric                                        " is too large to fit in a %" PRIu64
145914f1b3e8SDimitry Andric                                        " byte unsigned integer value.\n",
146014f1b3e8SDimitry Andric                                        uval64, (uint64_t)item_byte_size);
1461b1c73532SDimitry Andric           return;
1462f034231aSEd Maste         }
1463f034231aSEd Maste         buffer.PutMaxHex64(uval64, item_byte_size);
1464f034231aSEd Maste         break;
1465f034231aSEd Maste 
1466f034231aSEd Maste       case eFormatOctal:
1467ead24645SDimitry Andric         if (entry.ref().getAsInteger(8, uval64)) {
146814f1b3e8SDimitry Andric           result.AppendErrorWithFormat(
146914f1b3e8SDimitry Andric               "'%s' is not a valid octal string value.\n", entry.c_str());
1470b1c73532SDimitry Andric           return;
1471b60736ecSDimitry Andric         } else if (!llvm::isUIntN(item_byte_size * 8, uval64)) {
147214f1b3e8SDimitry Andric           result.AppendErrorWithFormat("Value %" PRIo64
147314f1b3e8SDimitry Andric                                        " is too large to fit in a %" PRIu64
147414f1b3e8SDimitry Andric                                        " byte unsigned integer value.\n",
147514f1b3e8SDimitry Andric                                        uval64, (uint64_t)item_byte_size);
1476b1c73532SDimitry Andric           return;
1477f034231aSEd Maste         }
1478f034231aSEd Maste         buffer.PutMaxHex64(uval64, item_byte_size);
1479f034231aSEd Maste         break;
1480f034231aSEd Maste       }
1481f034231aSEd Maste     }
1482f034231aSEd Maste 
148314f1b3e8SDimitry Andric     if (!buffer.GetString().empty()) {
1484b76161e4SDimitry Andric       Status error;
1485b1c73532SDimitry Andric       const char *buffer_data = buffer.GetString().data();
1486b1c73532SDimitry Andric       const size_t buffer_size = buffer.GetString().size();
1487b1c73532SDimitry Andric       const size_t write_size =
1488b1c73532SDimitry Andric           process->WriteMemory(addr, buffer_data, buffer_size, error);
1489b1c73532SDimitry Andric 
1490b1c73532SDimitry Andric       if (write_size != buffer_size) {
149114f1b3e8SDimitry Andric         result.AppendErrorWithFormat("Memory write to 0x%" PRIx64
149214f1b3e8SDimitry Andric                                      " failed: %s.\n",
149314f1b3e8SDimitry Andric                                      addr, error.AsCString());
1494b1c73532SDimitry Andric         return;
1495f034231aSEd Maste       }
1496f034231aSEd Maste     }
1497f034231aSEd Maste   }
1498f034231aSEd Maste 
1499f034231aSEd Maste   OptionGroupOptions m_option_group;
1500f034231aSEd Maste   OptionGroupFormat m_format_options;
1501f034231aSEd Maste   OptionGroupWriteMemory m_memory_options;
1502f034231aSEd Maste };
1503f034231aSEd Maste 
1504205afe67SEd Maste // Get malloc/free history of a memory address.
150514f1b3e8SDimitry Andric class CommandObjectMemoryHistory : public CommandObjectParsed {
1506205afe67SEd Maste public:
CommandObjectMemoryHistory(CommandInterpreter & interpreter)1507f3fbd1c0SDimitry Andric   CommandObjectMemoryHistory(CommandInterpreter &interpreter)
1508706b4fc4SDimitry Andric       : CommandObjectParsed(interpreter, "memory history",
1509706b4fc4SDimitry Andric                             "Print recorded stack traces for "
151014f1b3e8SDimitry Andric                             "allocation/deallocation events "
151114f1b3e8SDimitry Andric                             "associated with an address.",
151214f1b3e8SDimitry Andric                             nullptr,
151314f1b3e8SDimitry Andric                             eCommandRequiresTarget | eCommandRequiresProcess |
1514706b4fc4SDimitry Andric                                 eCommandProcessMustBePaused |
1515706b4fc4SDimitry Andric                                 eCommandProcessMustBeLaunched) {
1516205afe67SEd Maste     CommandArgumentEntry arg1;
1517205afe67SEd Maste     CommandArgumentData addr_arg;
1518205afe67SEd Maste 
1519205afe67SEd Maste     // Define the first (and only) variant of this arg.
1520205afe67SEd Maste     addr_arg.arg_type = eArgTypeAddress;
1521205afe67SEd Maste     addr_arg.arg_repetition = eArgRepeatPlain;
1522205afe67SEd Maste 
152314f1b3e8SDimitry Andric     // There is only one variant this argument could be; put it into the
152414f1b3e8SDimitry Andric     // argument entry.
1525205afe67SEd Maste     arg1.push_back(addr_arg);
1526205afe67SEd Maste 
1527205afe67SEd Maste     // Push the data for the first argument into the m_arguments vector.
1528205afe67SEd Maste     m_arguments.push_back(arg1);
1529205afe67SEd Maste   }
1530205afe67SEd Maste 
1531f3fbd1c0SDimitry Andric   ~CommandObjectMemoryHistory() override = default;
1532205afe67SEd Maste 
GetRepeatCommand(Args & current_command_args,uint32_t index)1533e3b55780SDimitry Andric   std::optional<std::string> GetRepeatCommand(Args &current_command_args,
153414f1b3e8SDimitry Andric                                               uint32_t index) override {
1535145449b1SDimitry Andric     return m_cmd_name;
1536205afe67SEd Maste   }
1537205afe67SEd Maste 
1538205afe67SEd Maste protected:
DoExecute(Args & command,CommandReturnObject & result)1539b1c73532SDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
1540205afe67SEd Maste     const size_t argc = command.GetArgumentCount();
1541205afe67SEd Maste 
154214f1b3e8SDimitry Andric     if (argc == 0 || argc > 1) {
154314f1b3e8SDimitry Andric       result.AppendErrorWithFormat("%s takes an address expression",
154414f1b3e8SDimitry Andric                                    m_cmd_name.c_str());
1545b1c73532SDimitry Andric       return;
1546205afe67SEd Maste     }
1547205afe67SEd Maste 
1548b76161e4SDimitry Andric     Status error;
1549f73363f1SDimitry Andric     lldb::addr_t addr = OptionArgParser::ToAddress(
1550ead24645SDimitry Andric         &m_exe_ctx, command[0].ref(), LLDB_INVALID_ADDRESS, &error);
1551205afe67SEd Maste 
155214f1b3e8SDimitry Andric     if (addr == LLDB_INVALID_ADDRESS) {
1553205afe67SEd Maste       result.AppendError("invalid address expression");
1554205afe67SEd Maste       result.AppendError(error.AsCString());
1555b1c73532SDimitry Andric       return;
1556205afe67SEd Maste     }
1557205afe67SEd Maste 
1558205afe67SEd Maste     Stream *output_stream = &result.GetOutputStream();
1559205afe67SEd Maste 
1560205afe67SEd Maste     const ProcessSP &process_sp = m_exe_ctx.GetProcessSP();
156114f1b3e8SDimitry Andric     const MemoryHistorySP &memory_history =
156214f1b3e8SDimitry Andric         MemoryHistory::FindPlugin(process_sp);
1563205afe67SEd Maste 
156414f1b3e8SDimitry Andric     if (!memory_history) {
1565205afe67SEd Maste       result.AppendError("no available memory history provider");
1566b1c73532SDimitry Andric       return;
1567205afe67SEd Maste     }
1568205afe67SEd Maste 
1569205afe67SEd Maste     HistoryThreads thread_list = memory_history->GetHistoryThreads(addr);
1570205afe67SEd Maste 
157114f1b3e8SDimitry Andric     const bool stop_format = false;
1572205afe67SEd Maste     for (auto thread : thread_list) {
157314f1b3e8SDimitry Andric       thread->GetStatus(*output_stream, 0, UINT32_MAX, 0, stop_format);
1574205afe67SEd Maste     }
1575205afe67SEd Maste 
1576205afe67SEd Maste     result.SetStatus(eReturnStatusSuccessFinishResult);
1577205afe67SEd Maste   }
1578205afe67SEd Maste };
1579205afe67SEd Maste 
1580f3fbd1c0SDimitry Andric // CommandObjectMemoryRegion
1581f3fbd1c0SDimitry Andric #pragma mark CommandObjectMemoryRegion
1582f3fbd1c0SDimitry Andric 
1583145449b1SDimitry Andric #define LLDB_OPTIONS_memory_region
1584145449b1SDimitry Andric #include "CommandOptions.inc"
1585145449b1SDimitry Andric 
158614f1b3e8SDimitry Andric class CommandObjectMemoryRegion : public CommandObjectParsed {
1587f3fbd1c0SDimitry Andric public:
1588145449b1SDimitry Andric   class OptionGroupMemoryRegion : public OptionGroup {
1589145449b1SDimitry Andric   public:
OptionGroupMemoryRegion()159008e8dd7bSDimitry Andric     OptionGroupMemoryRegion() : m_all(false, false) {}
1591145449b1SDimitry Andric 
1592145449b1SDimitry Andric     ~OptionGroupMemoryRegion() override = default;
1593145449b1SDimitry Andric 
GetDefinitions()1594145449b1SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1595e3b55780SDimitry Andric       return llvm::ArrayRef(g_memory_region_options);
1596145449b1SDimitry Andric     }
1597145449b1SDimitry Andric 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_value,ExecutionContext * execution_context)1598145449b1SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
1599145449b1SDimitry Andric                           ExecutionContext *execution_context) override {
1600145449b1SDimitry Andric       Status status;
1601145449b1SDimitry Andric       const int short_option = g_memory_region_options[option_idx].short_option;
1602145449b1SDimitry Andric 
1603145449b1SDimitry Andric       switch (short_option) {
1604145449b1SDimitry Andric       case 'a':
1605145449b1SDimitry Andric         m_all.SetCurrentValue(true);
1606145449b1SDimitry Andric         m_all.SetOptionWasSet();
1607145449b1SDimitry Andric         break;
1608145449b1SDimitry Andric       default:
1609145449b1SDimitry Andric         llvm_unreachable("Unimplemented option");
1610145449b1SDimitry Andric       }
1611145449b1SDimitry Andric 
1612145449b1SDimitry Andric       return status;
1613145449b1SDimitry Andric     }
1614145449b1SDimitry Andric 
OptionParsingStarting(ExecutionContext * execution_context)1615145449b1SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
1616145449b1SDimitry Andric       m_all.Clear();
1617145449b1SDimitry Andric     }
1618145449b1SDimitry Andric 
1619145449b1SDimitry Andric     OptionValueBoolean m_all;
1620145449b1SDimitry Andric   };
1621145449b1SDimitry Andric 
CommandObjectMemoryRegion(CommandInterpreter & interpreter)1622f3fbd1c0SDimitry Andric   CommandObjectMemoryRegion(CommandInterpreter &interpreter)
162314f1b3e8SDimitry Andric       : CommandObjectParsed(interpreter, "memory region",
162414f1b3e8SDimitry Andric                             "Get information on the memory region containing "
162514f1b3e8SDimitry Andric                             "an address in the current target process.",
1626145449b1SDimitry Andric                             "memory region <address-expression> (or --all)",
162714f1b3e8SDimitry Andric                             eCommandRequiresProcess | eCommandTryTargetAPILock |
1628145449b1SDimitry Andric                                 eCommandProcessMustBeLaunched) {
1629145449b1SDimitry Andric     // Address in option set 1.
1630145449b1SDimitry Andric     m_arguments.push_back(CommandArgumentEntry{CommandArgumentData(
1631145449b1SDimitry Andric         eArgTypeAddressOrExpression, eArgRepeatPlain, LLDB_OPT_SET_1)});
1632145449b1SDimitry Andric     // "--all" will go in option set 2.
1633145449b1SDimitry Andric     m_option_group.Append(&m_memory_region_options);
1634145449b1SDimitry Andric     m_option_group.Finalize();
1635145449b1SDimitry Andric   }
1636f3fbd1c0SDimitry Andric 
1637f3fbd1c0SDimitry Andric   ~CommandObjectMemoryRegion() override = default;
1638f3fbd1c0SDimitry Andric 
GetOptions()1639145449b1SDimitry Andric   Options *GetOptions() override { return &m_option_group; }
1640145449b1SDimitry Andric 
1641f3fbd1c0SDimitry Andric protected:
DumpRegion(CommandReturnObject & result,Target & target,const MemoryRegionInfo & range_info,lldb::addr_t load_addr)1642145449b1SDimitry Andric   void DumpRegion(CommandReturnObject &result, Target &target,
1643145449b1SDimitry Andric                   const MemoryRegionInfo &range_info, lldb::addr_t load_addr) {
1644145449b1SDimitry Andric     lldb_private::Address addr;
1645145449b1SDimitry Andric     ConstString section_name;
1646145449b1SDimitry Andric     if (target.ResolveLoadAddress(load_addr, addr)) {
1647145449b1SDimitry Andric       SectionSP section_sp(addr.GetSection());
1648145449b1SDimitry Andric       if (section_sp) {
1649145449b1SDimitry Andric         // Got the top most section, not the deepest section
1650145449b1SDimitry Andric         while (section_sp->GetParent())
1651145449b1SDimitry Andric           section_sp = section_sp->GetParent();
1652145449b1SDimitry Andric         section_name = section_sp->GetName();
1653145449b1SDimitry Andric       }
1654145449b1SDimitry Andric     }
1655145449b1SDimitry Andric 
1656145449b1SDimitry Andric     ConstString name = range_info.GetName();
1657145449b1SDimitry Andric     result.AppendMessageWithFormatv(
1658145449b1SDimitry Andric         "[{0:x16}-{1:x16}) {2:r}{3:w}{4:x}{5}{6}{7}{8}",
1659145449b1SDimitry Andric         range_info.GetRange().GetRangeBase(),
1660145449b1SDimitry Andric         range_info.GetRange().GetRangeEnd(), range_info.GetReadable(),
1661145449b1SDimitry Andric         range_info.GetWritable(), range_info.GetExecutable(), name ? " " : "",
1662145449b1SDimitry Andric         name, section_name ? " " : "", section_name);
1663145449b1SDimitry Andric     MemoryRegionInfo::OptionalBool memory_tagged = range_info.GetMemoryTagged();
1664145449b1SDimitry Andric     if (memory_tagged == MemoryRegionInfo::OptionalBool::eYes)
1665145449b1SDimitry Andric       result.AppendMessage("memory tagging: enabled");
1666145449b1SDimitry Andric 
1667e3b55780SDimitry Andric     const std::optional<std::vector<addr_t>> &dirty_page_list =
1668145449b1SDimitry Andric         range_info.GetDirtyPageList();
1669145449b1SDimitry Andric     if (dirty_page_list) {
1670e3b55780SDimitry Andric       const size_t page_count = dirty_page_list->size();
1671145449b1SDimitry Andric       result.AppendMessageWithFormat(
1672145449b1SDimitry Andric           "Modified memory (dirty) page list provided, %zu entries.\n",
1673145449b1SDimitry Andric           page_count);
1674145449b1SDimitry Andric       if (page_count > 0) {
1675145449b1SDimitry Andric         bool print_comma = false;
1676145449b1SDimitry Andric         result.AppendMessageWithFormat("Dirty pages: ");
1677145449b1SDimitry Andric         for (size_t i = 0; i < page_count; i++) {
1678145449b1SDimitry Andric           if (print_comma)
1679145449b1SDimitry Andric             result.AppendMessageWithFormat(", ");
1680145449b1SDimitry Andric           else
1681145449b1SDimitry Andric             print_comma = true;
1682145449b1SDimitry Andric           result.AppendMessageWithFormat("0x%" PRIx64, (*dirty_page_list)[i]);
1683145449b1SDimitry Andric         }
1684145449b1SDimitry Andric         result.AppendMessageWithFormat(".\n");
1685145449b1SDimitry Andric       }
1686145449b1SDimitry Andric     }
1687145449b1SDimitry Andric   }
1688145449b1SDimitry Andric 
DoExecute(Args & command,CommandReturnObject & result)1689b1c73532SDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
1690f3fbd1c0SDimitry Andric     ProcessSP process_sp = m_exe_ctx.GetProcessSP();
1691b60736ecSDimitry Andric     if (!process_sp) {
1692b60736ecSDimitry Andric       m_prev_end_addr = LLDB_INVALID_ADDRESS;
1693b60736ecSDimitry Andric       result.AppendError("invalid process");
1694b1c73532SDimitry Andric       return;
1695b60736ecSDimitry Andric     }
1696b60736ecSDimitry Andric 
1697b76161e4SDimitry Andric     Status error;
1698f3fbd1c0SDimitry Andric     lldb::addr_t load_addr = m_prev_end_addr;
1699f3fbd1c0SDimitry Andric     m_prev_end_addr = LLDB_INVALID_ADDRESS;
1700f3fbd1c0SDimitry Andric 
1701f3fbd1c0SDimitry Andric     const size_t argc = command.GetArgumentCount();
1702145449b1SDimitry Andric     const lldb::ABISP &abi = process_sp->GetABI();
1703145449b1SDimitry Andric 
1704145449b1SDimitry Andric     if (argc == 1) {
1705145449b1SDimitry Andric       if (m_memory_region_options.m_all) {
1706145449b1SDimitry Andric         result.AppendError(
1707145449b1SDimitry Andric             "The \"--all\" option cannot be used when an address "
1708145449b1SDimitry Andric             "argument is given");
1709b1c73532SDimitry Andric         return;
1710b60736ecSDimitry Andric       }
1711b60736ecSDimitry Andric 
1712ead24645SDimitry Andric       auto load_addr_str = command[0].ref();
1713f73363f1SDimitry Andric       load_addr = OptionArgParser::ToAddress(&m_exe_ctx, load_addr_str,
171414f1b3e8SDimitry Andric                                              LLDB_INVALID_ADDRESS, &error);
171514f1b3e8SDimitry Andric       if (error.Fail() || load_addr == LLDB_INVALID_ADDRESS) {
1716b60736ecSDimitry Andric         result.AppendErrorWithFormat("invalid address argument \"%s\": %s\n",
1717b60736ecSDimitry Andric                                      command[0].c_str(), error.AsCString());
1718b1c73532SDimitry Andric         return;
1719f3fbd1c0SDimitry Andric       }
1720145449b1SDimitry Andric     } else if (argc > 1 ||
1721145449b1SDimitry Andric                // When we're repeating the command, the previous end address is
1722145449b1SDimitry Andric                // used for load_addr. If that was 0xF...F then we must have
1723145449b1SDimitry Andric                // reached the end of memory.
1724145449b1SDimitry Andric                (argc == 0 && !m_memory_region_options.m_all &&
1725145449b1SDimitry Andric                 load_addr == LLDB_INVALID_ADDRESS) ||
1726145449b1SDimitry Andric                // If the target has non-address bits (tags, limited virtual
1727145449b1SDimitry Andric                // address size, etc.), the end of mappable memory will be lower
1728145449b1SDimitry Andric                // than that. So if we find any non-address bit set, we must be
1729145449b1SDimitry Andric                // at the end of the mappable range.
1730145449b1SDimitry Andric                (abi && (abi->FixAnyAddress(load_addr) != load_addr))) {
1731145449b1SDimitry Andric       result.AppendErrorWithFormat(
1732145449b1SDimitry Andric           "'%s' takes one argument or \"--all\" option:\nUsage: %s\n",
1733145449b1SDimitry Andric           m_cmd_name.c_str(), m_cmd_syntax.c_str());
1734b1c73532SDimitry Andric       return;
1735f3fbd1c0SDimitry Andric     }
1736f3fbd1c0SDimitry Andric 
1737b1c73532SDimitry Andric     // It is important that we track the address used to request the region as
1738145449b1SDimitry Andric     // this will give the correct section name in the case that regions overlap.
1739145449b1SDimitry Andric     // On Windows we get mutliple regions that start at the same place but are
1740145449b1SDimitry Andric     // different sizes and refer to different sections.
1741145449b1SDimitry Andric     std::vector<std::pair<lldb_private::MemoryRegionInfo, lldb::addr_t>>
1742145449b1SDimitry Andric         region_list;
1743145449b1SDimitry Andric     if (m_memory_region_options.m_all) {
1744145449b1SDimitry Andric       // We don't use GetMemoryRegions here because it doesn't include unmapped
1745145449b1SDimitry Andric       // areas like repeating the command would. So instead, emulate doing that.
1746145449b1SDimitry Andric       lldb::addr_t addr = 0;
1747145449b1SDimitry Andric       while (error.Success() && addr != LLDB_INVALID_ADDRESS &&
1748145449b1SDimitry Andric              // When there are non-address bits the last range will not extend
1749145449b1SDimitry Andric              // to LLDB_INVALID_ADDRESS but to the max virtual address.
1750145449b1SDimitry Andric              // This prevents us looping forever if that is the case.
1751e3b55780SDimitry Andric              (!abi || (abi->FixAnyAddress(addr) == addr))) {
1752145449b1SDimitry Andric         lldb_private::MemoryRegionInfo region_info;
1753145449b1SDimitry Andric         error = process_sp->GetMemoryRegionInfo(addr, region_info);
1754145449b1SDimitry Andric 
175514f1b3e8SDimitry Andric         if (error.Success()) {
1756145449b1SDimitry Andric           region_list.push_back({region_info, addr});
1757145449b1SDimitry Andric           addr = region_info.GetRange().GetRangeEnd();
1758f3fbd1c0SDimitry Andric         }
1759f3fbd1c0SDimitry Andric       }
1760145449b1SDimitry Andric     } else {
1761145449b1SDimitry Andric       lldb_private::MemoryRegionInfo region_info;
1762145449b1SDimitry Andric       error = process_sp->GetMemoryRegionInfo(load_addr, region_info);
1763145449b1SDimitry Andric       if (error.Success())
1764145449b1SDimitry Andric         region_list.push_back({region_info, load_addr});
1765344a3780SDimitry Andric     }
1766344a3780SDimitry Andric 
1767145449b1SDimitry Andric     if (error.Success()) {
1768145449b1SDimitry Andric       for (std::pair<MemoryRegionInfo, addr_t> &range : region_list) {
1769145449b1SDimitry Andric         DumpRegion(result, process_sp->GetTarget(), range.first, range.second);
1770145449b1SDimitry Andric         m_prev_end_addr = range.first.GetRange().GetRangeEnd();
1771145449b1SDimitry Andric       }
1772145449b1SDimitry Andric 
1773f3fbd1c0SDimitry Andric       result.SetStatus(eReturnStatusSuccessFinishResult);
1774b1c73532SDimitry Andric       return;
1775b60736ecSDimitry Andric     }
1776b60736ecSDimitry Andric 
1777f3fbd1c0SDimitry Andric     result.AppendErrorWithFormat("%s\n", error.AsCString());
1778f3fbd1c0SDimitry Andric   }
1779f3fbd1c0SDimitry Andric 
GetRepeatCommand(Args & current_command_args,uint32_t index)1780e3b55780SDimitry Andric   std::optional<std::string> GetRepeatCommand(Args &current_command_args,
178114f1b3e8SDimitry Andric                                               uint32_t index) override {
1782f3fbd1c0SDimitry Andric     // If we repeat this command, repeat it without any arguments so we can
1783f3fbd1c0SDimitry Andric     // show the next memory range
1784145449b1SDimitry Andric     return m_cmd_name;
1785f3fbd1c0SDimitry Andric   }
1786f3fbd1c0SDimitry Andric 
1787145449b1SDimitry Andric   lldb::addr_t m_prev_end_addr = LLDB_INVALID_ADDRESS;
1788145449b1SDimitry Andric 
1789145449b1SDimitry Andric   OptionGroupOptions m_option_group;
1790145449b1SDimitry Andric   OptionGroupMemoryRegion m_memory_region_options;
1791f3fbd1c0SDimitry Andric };
1792f034231aSEd Maste 
1793f034231aSEd Maste // CommandObjectMemory
1794f034231aSEd Maste 
CommandObjectMemory(CommandInterpreter & interpreter)1795f3fbd1c0SDimitry Andric CommandObjectMemory::CommandObjectMemory(CommandInterpreter &interpreter)
179614f1b3e8SDimitry Andric     : CommandObjectMultiword(
179714f1b3e8SDimitry Andric           interpreter, "memory",
179814f1b3e8SDimitry Andric           "Commands for operating on memory in the current target process.",
179914f1b3e8SDimitry Andric           "memory <subcommand> [<subcommand-options>]") {
180014f1b3e8SDimitry Andric   LoadSubCommand("find",
180114f1b3e8SDimitry Andric                  CommandObjectSP(new CommandObjectMemoryFind(interpreter)));
180214f1b3e8SDimitry Andric   LoadSubCommand("read",
180314f1b3e8SDimitry Andric                  CommandObjectSP(new CommandObjectMemoryRead(interpreter)));
180414f1b3e8SDimitry Andric   LoadSubCommand("write",
180514f1b3e8SDimitry Andric                  CommandObjectSP(new CommandObjectMemoryWrite(interpreter)));
180614f1b3e8SDimitry Andric   LoadSubCommand("history",
180714f1b3e8SDimitry Andric                  CommandObjectSP(new CommandObjectMemoryHistory(interpreter)));
180814f1b3e8SDimitry Andric   LoadSubCommand("region",
180914f1b3e8SDimitry Andric                  CommandObjectSP(new CommandObjectMemoryRegion(interpreter)));
1810344a3780SDimitry Andric   LoadSubCommand("tag",
1811344a3780SDimitry Andric                  CommandObjectSP(new CommandObjectMemoryTag(interpreter)));
1812f034231aSEd Maste }
1813f034231aSEd Maste 
1814f3fbd1c0SDimitry Andric CommandObjectMemory::~CommandObjectMemory() = default;
1815