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 ¤t_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 ¤t_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 ¤t_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