1dda28197Spatrick //===-- CommandObjectMemory.cpp -------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "CommandObjectMemory.h"
10be691f3bSpatrick #include "CommandObjectMemoryTag.h"
11061da546Spatrick #include "lldb/Core/DumpDataExtractor.h"
12061da546Spatrick #include "lldb/Core/Section.h"
13061da546Spatrick #include "lldb/Core/ValueObjectMemory.h"
14061da546Spatrick #include "lldb/Expression/ExpressionVariable.h"
15061da546Spatrick #include "lldb/Host/OptionParser.h"
16*f6aab3d8Srobert #include "lldb/Interpreter/CommandOptionArgumentTable.h"
17061da546Spatrick #include "lldb/Interpreter/CommandReturnObject.h"
18061da546Spatrick #include "lldb/Interpreter/OptionArgParser.h"
19061da546Spatrick #include "lldb/Interpreter/OptionGroupFormat.h"
20*f6aab3d8Srobert #include "lldb/Interpreter/OptionGroupMemoryTag.h"
21061da546Spatrick #include "lldb/Interpreter/OptionGroupOutputFile.h"
22061da546Spatrick #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
23061da546Spatrick #include "lldb/Interpreter/OptionValueLanguage.h"
24061da546Spatrick #include "lldb/Interpreter/OptionValueString.h"
25061da546Spatrick #include "lldb/Interpreter/Options.h"
26061da546Spatrick #include "lldb/Symbol/SymbolFile.h"
27061da546Spatrick #include "lldb/Symbol/TypeList.h"
28*f6aab3d8Srobert #include "lldb/Target/ABI.h"
29061da546Spatrick #include "lldb/Target/Language.h"
30061da546Spatrick #include "lldb/Target/MemoryHistory.h"
31061da546Spatrick #include "lldb/Target/MemoryRegionInfo.h"
32061da546Spatrick #include "lldb/Target/Process.h"
33061da546Spatrick #include "lldb/Target/StackFrame.h"
34061da546Spatrick #include "lldb/Target/Target.h"
35061da546Spatrick #include "lldb/Target/Thread.h"
36061da546Spatrick #include "lldb/Utility/Args.h"
37061da546Spatrick #include "lldb/Utility/DataBufferHeap.h"
38061da546Spatrick #include "lldb/Utility/StreamString.h"
39be691f3bSpatrick #include "llvm/Support/MathExtras.h"
40061da546Spatrick #include <cinttypes>
41061da546Spatrick #include <memory>
42*f6aab3d8Srobert #include <optional>
43061da546Spatrick
44061da546Spatrick using namespace lldb;
45061da546Spatrick using namespace lldb_private;
46061da546Spatrick
47061da546Spatrick #define LLDB_OPTIONS_memory_read
48061da546Spatrick #include "CommandOptions.inc"
49061da546Spatrick
50061da546Spatrick class OptionGroupReadMemory : public OptionGroup {
51061da546Spatrick public:
OptionGroupReadMemory()52061da546Spatrick OptionGroupReadMemory()
53*f6aab3d8Srobert : m_num_per_line(1, 1), m_offset(0, 0),
54be691f3bSpatrick m_language_for_type(eLanguageTypeUnknown) {}
55061da546Spatrick
56061da546Spatrick ~OptionGroupReadMemory() override = default;
57061da546Spatrick
GetDefinitions()58061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
59*f6aab3d8Srobert return llvm::ArrayRef(g_memory_read_options);
60061da546Spatrick }
61061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_value,ExecutionContext * execution_context)62061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
63061da546Spatrick ExecutionContext *execution_context) override {
64061da546Spatrick Status error;
65061da546Spatrick const int short_option = g_memory_read_options[option_idx].short_option;
66061da546Spatrick
67061da546Spatrick switch (short_option) {
68061da546Spatrick case 'l':
69061da546Spatrick error = m_num_per_line.SetValueFromString(option_value);
70061da546Spatrick if (m_num_per_line.GetCurrentValue() == 0)
71061da546Spatrick error.SetErrorStringWithFormat(
72061da546Spatrick "invalid value for --num-per-line option '%s'",
73061da546Spatrick option_value.str().c_str());
74061da546Spatrick break;
75061da546Spatrick
76061da546Spatrick case 'b':
77061da546Spatrick m_output_as_binary = true;
78061da546Spatrick break;
79061da546Spatrick
80061da546Spatrick case 't':
81061da546Spatrick error = m_view_as_type.SetValueFromString(option_value);
82061da546Spatrick break;
83061da546Spatrick
84061da546Spatrick case 'r':
85061da546Spatrick m_force = true;
86061da546Spatrick break;
87061da546Spatrick
88061da546Spatrick case 'x':
89061da546Spatrick error = m_language_for_type.SetValueFromString(option_value);
90061da546Spatrick break;
91061da546Spatrick
92061da546Spatrick case 'E':
93061da546Spatrick error = m_offset.SetValueFromString(option_value);
94061da546Spatrick break;
95061da546Spatrick
96061da546Spatrick default:
97061da546Spatrick llvm_unreachable("Unimplemented option");
98061da546Spatrick }
99061da546Spatrick return error;
100061da546Spatrick }
101061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)102061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
103061da546Spatrick m_num_per_line.Clear();
104061da546Spatrick m_output_as_binary = false;
105061da546Spatrick m_view_as_type.Clear();
106061da546Spatrick m_force = false;
107061da546Spatrick m_offset.Clear();
108061da546Spatrick m_language_for_type.Clear();
109061da546Spatrick }
110061da546Spatrick
FinalizeSettings(Target * target,OptionGroupFormat & format_options)111061da546Spatrick Status FinalizeSettings(Target *target, OptionGroupFormat &format_options) {
112061da546Spatrick Status error;
113061da546Spatrick OptionValueUInt64 &byte_size_value = format_options.GetByteSizeValue();
114061da546Spatrick OptionValueUInt64 &count_value = format_options.GetCountValue();
115061da546Spatrick const bool byte_size_option_set = byte_size_value.OptionWasSet();
116061da546Spatrick const bool num_per_line_option_set = m_num_per_line.OptionWasSet();
117061da546Spatrick const bool count_option_set = format_options.GetCountValue().OptionWasSet();
118061da546Spatrick
119061da546Spatrick switch (format_options.GetFormat()) {
120061da546Spatrick default:
121061da546Spatrick break;
122061da546Spatrick
123061da546Spatrick case eFormatBoolean:
124061da546Spatrick if (!byte_size_option_set)
125061da546Spatrick byte_size_value = 1;
126061da546Spatrick if (!num_per_line_option_set)
127061da546Spatrick m_num_per_line = 1;
128061da546Spatrick if (!count_option_set)
129061da546Spatrick format_options.GetCountValue() = 8;
130061da546Spatrick break;
131061da546Spatrick
132061da546Spatrick case eFormatCString:
133061da546Spatrick break;
134061da546Spatrick
135061da546Spatrick case eFormatInstruction:
136061da546Spatrick if (count_option_set)
137061da546Spatrick byte_size_value = target->GetArchitecture().GetMaximumOpcodeByteSize();
138061da546Spatrick m_num_per_line = 1;
139061da546Spatrick break;
140061da546Spatrick
141061da546Spatrick case eFormatAddressInfo:
142061da546Spatrick if (!byte_size_option_set)
143061da546Spatrick byte_size_value = target->GetArchitecture().GetAddressByteSize();
144061da546Spatrick m_num_per_line = 1;
145061da546Spatrick if (!count_option_set)
146061da546Spatrick format_options.GetCountValue() = 8;
147061da546Spatrick break;
148061da546Spatrick
149061da546Spatrick case eFormatPointer:
150061da546Spatrick byte_size_value = target->GetArchitecture().GetAddressByteSize();
151061da546Spatrick if (!num_per_line_option_set)
152061da546Spatrick m_num_per_line = 4;
153061da546Spatrick if (!count_option_set)
154061da546Spatrick format_options.GetCountValue() = 8;
155061da546Spatrick break;
156061da546Spatrick
157061da546Spatrick case eFormatBinary:
158061da546Spatrick case eFormatFloat:
159061da546Spatrick case eFormatOctal:
160061da546Spatrick case eFormatDecimal:
161061da546Spatrick case eFormatEnum:
162061da546Spatrick case eFormatUnicode8:
163061da546Spatrick case eFormatUnicode16:
164061da546Spatrick case eFormatUnicode32:
165061da546Spatrick case eFormatUnsigned:
166061da546Spatrick case eFormatHexFloat:
167061da546Spatrick if (!byte_size_option_set)
168061da546Spatrick byte_size_value = 4;
169061da546Spatrick if (!num_per_line_option_set)
170061da546Spatrick m_num_per_line = 1;
171061da546Spatrick if (!count_option_set)
172061da546Spatrick format_options.GetCountValue() = 8;
173061da546Spatrick break;
174061da546Spatrick
175061da546Spatrick case eFormatBytes:
176061da546Spatrick case eFormatBytesWithASCII:
177061da546Spatrick if (byte_size_option_set) {
178061da546Spatrick if (byte_size_value > 1)
179061da546Spatrick error.SetErrorStringWithFormat(
180061da546Spatrick "display format (bytes/bytes with ASCII) conflicts with the "
181061da546Spatrick "specified byte size %" PRIu64 "\n"
182061da546Spatrick "\tconsider using a different display format or don't specify "
183061da546Spatrick "the byte size.",
184061da546Spatrick byte_size_value.GetCurrentValue());
185061da546Spatrick } else
186061da546Spatrick byte_size_value = 1;
187061da546Spatrick if (!num_per_line_option_set)
188061da546Spatrick m_num_per_line = 16;
189061da546Spatrick if (!count_option_set)
190061da546Spatrick format_options.GetCountValue() = 32;
191061da546Spatrick break;
192061da546Spatrick
193061da546Spatrick case eFormatCharArray:
194061da546Spatrick case eFormatChar:
195061da546Spatrick case eFormatCharPrintable:
196061da546Spatrick if (!byte_size_option_set)
197061da546Spatrick byte_size_value = 1;
198061da546Spatrick if (!num_per_line_option_set)
199061da546Spatrick m_num_per_line = 32;
200061da546Spatrick if (!count_option_set)
201061da546Spatrick format_options.GetCountValue() = 64;
202061da546Spatrick break;
203061da546Spatrick
204061da546Spatrick case eFormatComplex:
205061da546Spatrick if (!byte_size_option_set)
206061da546Spatrick byte_size_value = 8;
207061da546Spatrick if (!num_per_line_option_set)
208061da546Spatrick m_num_per_line = 1;
209061da546Spatrick if (!count_option_set)
210061da546Spatrick format_options.GetCountValue() = 8;
211061da546Spatrick break;
212061da546Spatrick
213061da546Spatrick case eFormatComplexInteger:
214061da546Spatrick if (!byte_size_option_set)
215061da546Spatrick byte_size_value = 8;
216061da546Spatrick if (!num_per_line_option_set)
217061da546Spatrick m_num_per_line = 1;
218061da546Spatrick if (!count_option_set)
219061da546Spatrick format_options.GetCountValue() = 8;
220061da546Spatrick break;
221061da546Spatrick
222061da546Spatrick case eFormatHex:
223061da546Spatrick if (!byte_size_option_set)
224061da546Spatrick byte_size_value = 4;
225061da546Spatrick if (!num_per_line_option_set) {
226061da546Spatrick switch (byte_size_value) {
227061da546Spatrick case 1:
228061da546Spatrick case 2:
229061da546Spatrick m_num_per_line = 8;
230061da546Spatrick break;
231061da546Spatrick case 4:
232061da546Spatrick m_num_per_line = 4;
233061da546Spatrick break;
234061da546Spatrick case 8:
235061da546Spatrick m_num_per_line = 2;
236061da546Spatrick break;
237061da546Spatrick default:
238061da546Spatrick m_num_per_line = 1;
239061da546Spatrick break;
240061da546Spatrick }
241061da546Spatrick }
242061da546Spatrick if (!count_option_set)
243061da546Spatrick count_value = 8;
244061da546Spatrick break;
245061da546Spatrick
246061da546Spatrick case eFormatVectorOfChar:
247061da546Spatrick case eFormatVectorOfSInt8:
248061da546Spatrick case eFormatVectorOfUInt8:
249061da546Spatrick case eFormatVectorOfSInt16:
250061da546Spatrick case eFormatVectorOfUInt16:
251061da546Spatrick case eFormatVectorOfSInt32:
252061da546Spatrick case eFormatVectorOfUInt32:
253061da546Spatrick case eFormatVectorOfSInt64:
254061da546Spatrick case eFormatVectorOfUInt64:
255061da546Spatrick case eFormatVectorOfFloat16:
256061da546Spatrick case eFormatVectorOfFloat32:
257061da546Spatrick case eFormatVectorOfFloat64:
258061da546Spatrick case eFormatVectorOfUInt128:
259061da546Spatrick if (!byte_size_option_set)
260061da546Spatrick byte_size_value = 128;
261061da546Spatrick if (!num_per_line_option_set)
262061da546Spatrick m_num_per_line = 1;
263061da546Spatrick if (!count_option_set)
264061da546Spatrick count_value = 4;
265061da546Spatrick break;
266061da546Spatrick }
267061da546Spatrick return error;
268061da546Spatrick }
269061da546Spatrick
AnyOptionWasSet() const270061da546Spatrick bool AnyOptionWasSet() const {
271061da546Spatrick return m_num_per_line.OptionWasSet() || m_output_as_binary ||
272061da546Spatrick m_view_as_type.OptionWasSet() || m_offset.OptionWasSet() ||
273061da546Spatrick m_language_for_type.OptionWasSet();
274061da546Spatrick }
275061da546Spatrick
276061da546Spatrick OptionValueUInt64 m_num_per_line;
277be691f3bSpatrick bool m_output_as_binary = false;
278061da546Spatrick OptionValueString m_view_as_type;
279*f6aab3d8Srobert bool m_force = false;
280061da546Spatrick OptionValueUInt64 m_offset;
281061da546Spatrick OptionValueLanguage m_language_for_type;
282061da546Spatrick };
283061da546Spatrick
284061da546Spatrick // Read memory from the inferior process
285061da546Spatrick class CommandObjectMemoryRead : public CommandObjectParsed {
286061da546Spatrick public:
CommandObjectMemoryRead(CommandInterpreter & interpreter)287061da546Spatrick CommandObjectMemoryRead(CommandInterpreter &interpreter)
288061da546Spatrick : CommandObjectParsed(
289061da546Spatrick interpreter, "memory read",
290061da546Spatrick "Read from the memory of the current target process.", nullptr,
291061da546Spatrick eCommandRequiresTarget | eCommandProcessMustBePaused),
292*f6aab3d8Srobert m_format_options(eFormatBytesWithASCII, 1, 8),
293*f6aab3d8Srobert m_memory_tag_options(/*note_binary=*/true),
294*f6aab3d8Srobert m_prev_format_options(eFormatBytesWithASCII, 1, 8) {
295061da546Spatrick CommandArgumentEntry arg1;
296061da546Spatrick CommandArgumentEntry arg2;
297061da546Spatrick CommandArgumentData start_addr_arg;
298061da546Spatrick CommandArgumentData end_addr_arg;
299061da546Spatrick
300061da546Spatrick // Define the first (and only) variant of this arg.
301061da546Spatrick start_addr_arg.arg_type = eArgTypeAddressOrExpression;
302061da546Spatrick start_addr_arg.arg_repetition = eArgRepeatPlain;
303061da546Spatrick
304061da546Spatrick // There is only one variant this argument could be; put it into the
305061da546Spatrick // argument entry.
306061da546Spatrick arg1.push_back(start_addr_arg);
307061da546Spatrick
308061da546Spatrick // Define the first (and only) variant of this arg.
309061da546Spatrick end_addr_arg.arg_type = eArgTypeAddressOrExpression;
310061da546Spatrick end_addr_arg.arg_repetition = eArgRepeatOptional;
311061da546Spatrick
312061da546Spatrick // There is only one variant this argument could be; put it into the
313061da546Spatrick // argument entry.
314061da546Spatrick arg2.push_back(end_addr_arg);
315061da546Spatrick
316061da546Spatrick // Push the data for the first argument into the m_arguments vector.
317061da546Spatrick m_arguments.push_back(arg1);
318061da546Spatrick m_arguments.push_back(arg2);
319061da546Spatrick
320061da546Spatrick // Add the "--format" and "--count" options to group 1 and 3
321061da546Spatrick m_option_group.Append(&m_format_options,
322061da546Spatrick OptionGroupFormat::OPTION_GROUP_FORMAT |
323061da546Spatrick OptionGroupFormat::OPTION_GROUP_COUNT,
324061da546Spatrick LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3);
325061da546Spatrick m_option_group.Append(&m_format_options,
326061da546Spatrick OptionGroupFormat::OPTION_GROUP_GDB_FMT,
327061da546Spatrick LLDB_OPT_SET_1 | LLDB_OPT_SET_3);
328061da546Spatrick // Add the "--size" option to group 1 and 2
329061da546Spatrick m_option_group.Append(&m_format_options,
330061da546Spatrick OptionGroupFormat::OPTION_GROUP_SIZE,
331061da546Spatrick LLDB_OPT_SET_1 | LLDB_OPT_SET_2);
332061da546Spatrick m_option_group.Append(&m_memory_options);
333061da546Spatrick m_option_group.Append(&m_outfile_options, LLDB_OPT_SET_ALL,
334061da546Spatrick LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3);
335061da546Spatrick m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_3);
336*f6aab3d8Srobert m_option_group.Append(&m_memory_tag_options, LLDB_OPT_SET_ALL,
337*f6aab3d8Srobert LLDB_OPT_SET_ALL);
338061da546Spatrick m_option_group.Finalize();
339061da546Spatrick }
340061da546Spatrick
341061da546Spatrick ~CommandObjectMemoryRead() override = default;
342061da546Spatrick
GetOptions()343061da546Spatrick Options *GetOptions() override { return &m_option_group; }
344061da546Spatrick
GetRepeatCommand(Args & current_command_args,uint32_t index)345*f6aab3d8Srobert std::optional<std::string> GetRepeatCommand(Args ¤t_command_args,
346061da546Spatrick uint32_t index) override {
347*f6aab3d8Srobert return m_cmd_name;
348061da546Spatrick }
349061da546Spatrick
350061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)351061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
352061da546Spatrick // No need to check "target" for validity as eCommandRequiresTarget ensures
353061da546Spatrick // it is valid
354061da546Spatrick Target *target = m_exe_ctx.GetTargetPtr();
355061da546Spatrick
356061da546Spatrick const size_t argc = command.GetArgumentCount();
357061da546Spatrick
358061da546Spatrick if ((argc == 0 && m_next_addr == LLDB_INVALID_ADDRESS) || argc > 2) {
359061da546Spatrick result.AppendErrorWithFormat("%s takes a start address expression with "
360061da546Spatrick "an optional end address expression.\n",
361061da546Spatrick m_cmd_name.c_str());
362be691f3bSpatrick result.AppendWarning("Expressions should be quoted if they contain "
363be691f3bSpatrick "spaces or other special characters.");
364061da546Spatrick return false;
365061da546Spatrick }
366061da546Spatrick
367061da546Spatrick CompilerType compiler_type;
368061da546Spatrick Status error;
369061da546Spatrick
370061da546Spatrick const char *view_as_type_cstr =
371061da546Spatrick m_memory_options.m_view_as_type.GetCurrentValue();
372061da546Spatrick if (view_as_type_cstr && view_as_type_cstr[0]) {
373061da546Spatrick // We are viewing memory as a type
374061da546Spatrick
375061da546Spatrick const bool exact_match = false;
376061da546Spatrick TypeList type_list;
377061da546Spatrick uint32_t reference_count = 0;
378061da546Spatrick uint32_t pointer_count = 0;
379061da546Spatrick size_t idx;
380061da546Spatrick
381061da546Spatrick #define ALL_KEYWORDS \
382061da546Spatrick KEYWORD("const") \
383061da546Spatrick KEYWORD("volatile") \
384061da546Spatrick KEYWORD("restrict") \
385061da546Spatrick KEYWORD("struct") \
386061da546Spatrick KEYWORD("class") \
387061da546Spatrick KEYWORD("union")
388061da546Spatrick
389061da546Spatrick #define KEYWORD(s) s,
390061da546Spatrick static const char *g_keywords[] = {ALL_KEYWORDS};
391061da546Spatrick #undef KEYWORD
392061da546Spatrick
393061da546Spatrick #define KEYWORD(s) (sizeof(s) - 1),
394061da546Spatrick static const int g_keyword_lengths[] = {ALL_KEYWORDS};
395061da546Spatrick #undef KEYWORD
396061da546Spatrick
397061da546Spatrick #undef ALL_KEYWORDS
398061da546Spatrick
399061da546Spatrick static size_t g_num_keywords = sizeof(g_keywords) / sizeof(const char *);
400061da546Spatrick std::string type_str(view_as_type_cstr);
401061da546Spatrick
402061da546Spatrick // Remove all instances of g_keywords that are followed by spaces
403061da546Spatrick for (size_t i = 0; i < g_num_keywords; ++i) {
404061da546Spatrick const char *keyword = g_keywords[i];
405061da546Spatrick int keyword_len = g_keyword_lengths[i];
406061da546Spatrick
407061da546Spatrick idx = 0;
408061da546Spatrick while ((idx = type_str.find(keyword, idx)) != std::string::npos) {
409061da546Spatrick if (type_str[idx + keyword_len] == ' ' ||
410061da546Spatrick type_str[idx + keyword_len] == '\t') {
411061da546Spatrick type_str.erase(idx, keyword_len + 1);
412061da546Spatrick idx = 0;
413061da546Spatrick } else {
414061da546Spatrick idx += keyword_len;
415061da546Spatrick }
416061da546Spatrick }
417061da546Spatrick }
418061da546Spatrick bool done = type_str.empty();
419061da546Spatrick //
420061da546Spatrick idx = type_str.find_first_not_of(" \t");
421061da546Spatrick if (idx > 0 && idx != std::string::npos)
422061da546Spatrick type_str.erase(0, idx);
423061da546Spatrick while (!done) {
424061da546Spatrick // Strip trailing spaces
425061da546Spatrick if (type_str.empty())
426061da546Spatrick done = true;
427061da546Spatrick else {
428061da546Spatrick switch (type_str[type_str.size() - 1]) {
429061da546Spatrick case '*':
430061da546Spatrick ++pointer_count;
431*f6aab3d8Srobert [[fallthrough]];
432061da546Spatrick case ' ':
433061da546Spatrick case '\t':
434061da546Spatrick type_str.erase(type_str.size() - 1);
435061da546Spatrick break;
436061da546Spatrick
437061da546Spatrick case '&':
438061da546Spatrick if (reference_count == 0) {
439061da546Spatrick reference_count = 1;
440061da546Spatrick type_str.erase(type_str.size() - 1);
441061da546Spatrick } else {
442061da546Spatrick result.AppendErrorWithFormat("invalid type string: '%s'\n",
443061da546Spatrick view_as_type_cstr);
444061da546Spatrick return false;
445061da546Spatrick }
446061da546Spatrick break;
447061da546Spatrick
448061da546Spatrick default:
449061da546Spatrick done = true;
450061da546Spatrick break;
451061da546Spatrick }
452061da546Spatrick }
453061da546Spatrick }
454061da546Spatrick
455061da546Spatrick llvm::DenseSet<lldb_private::SymbolFile *> searched_symbol_files;
456061da546Spatrick ConstString lookup_type_name(type_str.c_str());
457061da546Spatrick StackFrame *frame = m_exe_ctx.GetFramePtr();
458061da546Spatrick ModuleSP search_first;
459061da546Spatrick if (frame) {
460061da546Spatrick search_first = frame->GetSymbolContext(eSymbolContextModule).module_sp;
461061da546Spatrick }
462061da546Spatrick target->GetImages().FindTypes(search_first.get(), lookup_type_name,
463061da546Spatrick exact_match, 1, searched_symbol_files,
464061da546Spatrick type_list);
465061da546Spatrick
466061da546Spatrick if (type_list.GetSize() == 0 && lookup_type_name.GetCString()) {
467061da546Spatrick LanguageType language_for_type =
468061da546Spatrick m_memory_options.m_language_for_type.GetCurrentValue();
469061da546Spatrick std::set<LanguageType> languages_to_check;
470061da546Spatrick if (language_for_type != eLanguageTypeUnknown) {
471061da546Spatrick languages_to_check.insert(language_for_type);
472061da546Spatrick } else {
473061da546Spatrick languages_to_check = Language::GetSupportedLanguages();
474061da546Spatrick }
475061da546Spatrick
476061da546Spatrick std::set<CompilerType> user_defined_types;
477061da546Spatrick for (auto lang : languages_to_check) {
478061da546Spatrick if (auto *persistent_vars =
479061da546Spatrick target->GetPersistentExpressionStateForLanguage(lang)) {
480*f6aab3d8Srobert if (std::optional<CompilerType> type =
481061da546Spatrick persistent_vars->GetCompilerTypeFromPersistentDecl(
482061da546Spatrick lookup_type_name)) {
483061da546Spatrick user_defined_types.emplace(*type);
484061da546Spatrick }
485061da546Spatrick }
486061da546Spatrick }
487061da546Spatrick
488061da546Spatrick if (user_defined_types.size() > 1) {
489061da546Spatrick result.AppendErrorWithFormat(
490061da546Spatrick "Mutiple types found matching raw type '%s', please disambiguate "
491061da546Spatrick "by specifying the language with -x",
492061da546Spatrick lookup_type_name.GetCString());
493061da546Spatrick return false;
494061da546Spatrick }
495061da546Spatrick
496061da546Spatrick if (user_defined_types.size() == 1) {
497061da546Spatrick compiler_type = *user_defined_types.begin();
498061da546Spatrick }
499061da546Spatrick }
500061da546Spatrick
501061da546Spatrick if (!compiler_type.IsValid()) {
502061da546Spatrick if (type_list.GetSize() == 0) {
503061da546Spatrick result.AppendErrorWithFormat("unable to find any types that match "
504061da546Spatrick "the raw type '%s' for full type '%s'\n",
505061da546Spatrick lookup_type_name.GetCString(),
506061da546Spatrick view_as_type_cstr);
507061da546Spatrick return false;
508061da546Spatrick } else {
509061da546Spatrick TypeSP type_sp(type_list.GetTypeAtIndex(0));
510061da546Spatrick compiler_type = type_sp->GetFullCompilerType();
511061da546Spatrick }
512061da546Spatrick }
513061da546Spatrick
514061da546Spatrick while (pointer_count > 0) {
515061da546Spatrick CompilerType pointer_type = compiler_type.GetPointerType();
516061da546Spatrick if (pointer_type.IsValid())
517061da546Spatrick compiler_type = pointer_type;
518061da546Spatrick else {
519061da546Spatrick result.AppendError("unable make a pointer type\n");
520061da546Spatrick return false;
521061da546Spatrick }
522061da546Spatrick --pointer_count;
523061da546Spatrick }
524061da546Spatrick
525*f6aab3d8Srobert std::optional<uint64_t> size = compiler_type.GetByteSize(nullptr);
526061da546Spatrick if (!size) {
527061da546Spatrick result.AppendErrorWithFormat(
528061da546Spatrick "unable to get the byte size of the type '%s'\n",
529061da546Spatrick view_as_type_cstr);
530061da546Spatrick return false;
531061da546Spatrick }
532061da546Spatrick m_format_options.GetByteSizeValue() = *size;
533061da546Spatrick
534061da546Spatrick if (!m_format_options.GetCountValue().OptionWasSet())
535061da546Spatrick m_format_options.GetCountValue() = 1;
536061da546Spatrick } else {
537061da546Spatrick error = m_memory_options.FinalizeSettings(target, m_format_options);
538061da546Spatrick }
539061da546Spatrick
540061da546Spatrick // Look for invalid combinations of settings
541061da546Spatrick if (error.Fail()) {
542061da546Spatrick result.AppendError(error.AsCString());
543061da546Spatrick return false;
544061da546Spatrick }
545061da546Spatrick
546061da546Spatrick lldb::addr_t addr;
547061da546Spatrick size_t total_byte_size = 0;
548061da546Spatrick if (argc == 0) {
549061da546Spatrick // Use the last address and byte size and all options as they were if no
550061da546Spatrick // options have been set
551061da546Spatrick addr = m_next_addr;
552061da546Spatrick total_byte_size = m_prev_byte_size;
553061da546Spatrick compiler_type = m_prev_compiler_type;
554061da546Spatrick if (!m_format_options.AnyOptionWasSet() &&
555061da546Spatrick !m_memory_options.AnyOptionWasSet() &&
556061da546Spatrick !m_outfile_options.AnyOptionWasSet() &&
557*f6aab3d8Srobert !m_varobj_options.AnyOptionWasSet() &&
558*f6aab3d8Srobert !m_memory_tag_options.AnyOptionWasSet()) {
559061da546Spatrick m_format_options = m_prev_format_options;
560061da546Spatrick m_memory_options = m_prev_memory_options;
561061da546Spatrick m_outfile_options = m_prev_outfile_options;
562061da546Spatrick m_varobj_options = m_prev_varobj_options;
563*f6aab3d8Srobert m_memory_tag_options = m_prev_memory_tag_options;
564061da546Spatrick }
565061da546Spatrick }
566061da546Spatrick
567061da546Spatrick size_t item_count = m_format_options.GetCountValue().GetCurrentValue();
568061da546Spatrick
569061da546Spatrick // TODO For non-8-bit byte addressable architectures this needs to be
570061da546Spatrick // revisited to fully support all lldb's range of formatting options.
571061da546Spatrick // Furthermore code memory reads (for those architectures) will not be
572061da546Spatrick // correctly formatted even w/o formatting options.
573061da546Spatrick size_t item_byte_size =
574061da546Spatrick target->GetArchitecture().GetDataByteSize() > 1
575061da546Spatrick ? target->GetArchitecture().GetDataByteSize()
576061da546Spatrick : m_format_options.GetByteSizeValue().GetCurrentValue();
577061da546Spatrick
578061da546Spatrick const size_t num_per_line =
579061da546Spatrick m_memory_options.m_num_per_line.GetCurrentValue();
580061da546Spatrick
581061da546Spatrick if (total_byte_size == 0) {
582061da546Spatrick total_byte_size = item_count * item_byte_size;
583061da546Spatrick if (total_byte_size == 0)
584061da546Spatrick total_byte_size = 32;
585061da546Spatrick }
586061da546Spatrick
587061da546Spatrick if (argc > 0)
588061da546Spatrick addr = OptionArgParser::ToAddress(&m_exe_ctx, command[0].ref(),
589061da546Spatrick LLDB_INVALID_ADDRESS, &error);
590061da546Spatrick
591061da546Spatrick if (addr == LLDB_INVALID_ADDRESS) {
592061da546Spatrick result.AppendError("invalid start address expression.");
593061da546Spatrick result.AppendError(error.AsCString());
594061da546Spatrick return false;
595061da546Spatrick }
596061da546Spatrick
597*f6aab3d8Srobert ABISP abi;
598*f6aab3d8Srobert if (Process *proc = m_exe_ctx.GetProcessPtr())
599*f6aab3d8Srobert abi = proc->GetABI();
600*f6aab3d8Srobert
601*f6aab3d8Srobert if (abi)
602*f6aab3d8Srobert addr = abi->FixDataAddress(addr);
603*f6aab3d8Srobert
604061da546Spatrick if (argc == 2) {
605061da546Spatrick lldb::addr_t end_addr = OptionArgParser::ToAddress(
606061da546Spatrick &m_exe_ctx, command[1].ref(), LLDB_INVALID_ADDRESS, nullptr);
607*f6aab3d8Srobert if (end_addr != LLDB_INVALID_ADDRESS && abi)
608*f6aab3d8Srobert end_addr = abi->FixDataAddress(end_addr);
609*f6aab3d8Srobert
610061da546Spatrick if (end_addr == LLDB_INVALID_ADDRESS) {
611061da546Spatrick result.AppendError("invalid end address expression.");
612061da546Spatrick result.AppendError(error.AsCString());
613061da546Spatrick return false;
614061da546Spatrick } else if (end_addr <= addr) {
615061da546Spatrick result.AppendErrorWithFormat(
616061da546Spatrick "end address (0x%" PRIx64
617be691f3bSpatrick ") must be greater than the start address (0x%" PRIx64 ").\n",
618061da546Spatrick end_addr, addr);
619061da546Spatrick return false;
620061da546Spatrick } else if (m_format_options.GetCountValue().OptionWasSet()) {
621061da546Spatrick result.AppendErrorWithFormat(
622061da546Spatrick "specify either the end address (0x%" PRIx64
623061da546Spatrick ") or the count (--count %" PRIu64 "), not both.\n",
624061da546Spatrick end_addr, (uint64_t)item_count);
625061da546Spatrick return false;
626061da546Spatrick }
627061da546Spatrick
628061da546Spatrick total_byte_size = end_addr - addr;
629061da546Spatrick item_count = total_byte_size / item_byte_size;
630061da546Spatrick }
631061da546Spatrick
632061da546Spatrick uint32_t max_unforced_size = target->GetMaximumMemReadSize();
633061da546Spatrick
634061da546Spatrick if (total_byte_size > max_unforced_size && !m_memory_options.m_force) {
635061da546Spatrick result.AppendErrorWithFormat(
636061da546Spatrick "Normally, \'memory read\' will not read over %" PRIu32
637061da546Spatrick " bytes of data.\n",
638061da546Spatrick max_unforced_size);
639061da546Spatrick result.AppendErrorWithFormat(
640061da546Spatrick "Please use --force to override this restriction just once.\n");
641061da546Spatrick result.AppendErrorWithFormat("or set target.max-memory-read-size if you "
642061da546Spatrick "will often need a larger limit.\n");
643061da546Spatrick return false;
644061da546Spatrick }
645061da546Spatrick
646*f6aab3d8Srobert WritableDataBufferSP data_sp;
647061da546Spatrick size_t bytes_read = 0;
648061da546Spatrick if (compiler_type.GetOpaqueQualType()) {
649061da546Spatrick // Make sure we don't display our type as ASCII bytes like the default
650061da546Spatrick // memory read
651061da546Spatrick if (!m_format_options.GetFormatValue().OptionWasSet())
652061da546Spatrick m_format_options.GetFormatValue().SetCurrentValue(eFormatDefault);
653061da546Spatrick
654*f6aab3d8Srobert std::optional<uint64_t> size = compiler_type.GetByteSize(nullptr);
655061da546Spatrick if (!size) {
656061da546Spatrick result.AppendError("can't get size of type");
657061da546Spatrick return false;
658061da546Spatrick }
659061da546Spatrick bytes_read = *size * m_format_options.GetCountValue().GetCurrentValue();
660061da546Spatrick
661061da546Spatrick if (argc > 0)
662061da546Spatrick addr = addr + (*size * m_memory_options.m_offset.GetCurrentValue());
663061da546Spatrick } else if (m_format_options.GetFormatValue().GetCurrentValue() !=
664061da546Spatrick eFormatCString) {
665061da546Spatrick data_sp = std::make_shared<DataBufferHeap>(total_byte_size, '\0');
666061da546Spatrick if (data_sp->GetBytes() == nullptr) {
667061da546Spatrick result.AppendErrorWithFormat(
668061da546Spatrick "can't allocate 0x%" PRIx32
669061da546Spatrick " bytes for the memory read buffer, specify a smaller size to read",
670061da546Spatrick (uint32_t)total_byte_size);
671061da546Spatrick return false;
672061da546Spatrick }
673061da546Spatrick
674061da546Spatrick Address address(addr, nullptr);
675be691f3bSpatrick bytes_read = target->ReadMemory(address, data_sp->GetBytes(),
676be691f3bSpatrick data_sp->GetByteSize(), error, true);
677061da546Spatrick if (bytes_read == 0) {
678061da546Spatrick const char *error_cstr = error.AsCString();
679061da546Spatrick if (error_cstr && error_cstr[0]) {
680061da546Spatrick result.AppendError(error_cstr);
681061da546Spatrick } else {
682061da546Spatrick result.AppendErrorWithFormat(
683061da546Spatrick "failed to read memory from 0x%" PRIx64 ".\n", addr);
684061da546Spatrick }
685061da546Spatrick return false;
686061da546Spatrick }
687061da546Spatrick
688061da546Spatrick if (bytes_read < total_byte_size)
689061da546Spatrick result.AppendWarningWithFormat(
690061da546Spatrick "Not all bytes (%" PRIu64 "/%" PRIu64
691061da546Spatrick ") were able to be read from 0x%" PRIx64 ".\n",
692061da546Spatrick (uint64_t)bytes_read, (uint64_t)total_byte_size, addr);
693061da546Spatrick } else {
694061da546Spatrick // we treat c-strings as a special case because they do not have a fixed
695061da546Spatrick // size
696061da546Spatrick if (m_format_options.GetByteSizeValue().OptionWasSet() &&
697061da546Spatrick !m_format_options.HasGDBFormat())
698061da546Spatrick item_byte_size = m_format_options.GetByteSizeValue().GetCurrentValue();
699061da546Spatrick else
700061da546Spatrick item_byte_size = target->GetMaximumSizeOfStringSummary();
701061da546Spatrick if (!m_format_options.GetCountValue().OptionWasSet())
702061da546Spatrick item_count = 1;
703061da546Spatrick data_sp = std::make_shared<DataBufferHeap>(
704061da546Spatrick (item_byte_size + 1) * item_count,
705061da546Spatrick '\0'); // account for NULLs as necessary
706061da546Spatrick if (data_sp->GetBytes() == nullptr) {
707061da546Spatrick result.AppendErrorWithFormat(
708061da546Spatrick "can't allocate 0x%" PRIx64
709061da546Spatrick " bytes for the memory read buffer, specify a smaller size to read",
710061da546Spatrick (uint64_t)((item_byte_size + 1) * item_count));
711061da546Spatrick return false;
712061da546Spatrick }
713061da546Spatrick uint8_t *data_ptr = data_sp->GetBytes();
714061da546Spatrick auto data_addr = addr;
715061da546Spatrick auto count = item_count;
716061da546Spatrick item_count = 0;
717061da546Spatrick bool break_on_no_NULL = false;
718061da546Spatrick while (item_count < count) {
719061da546Spatrick std::string buffer;
720061da546Spatrick buffer.resize(item_byte_size + 1, 0);
721061da546Spatrick Status error;
722061da546Spatrick size_t read = target->ReadCStringFromMemory(data_addr, &buffer[0],
723061da546Spatrick item_byte_size + 1, error);
724061da546Spatrick if (error.Fail()) {
725061da546Spatrick result.AppendErrorWithFormat(
726061da546Spatrick "failed to read memory from 0x%" PRIx64 ".\n", addr);
727061da546Spatrick return false;
728061da546Spatrick }
729061da546Spatrick
730061da546Spatrick if (item_byte_size == read) {
731061da546Spatrick result.AppendWarningWithFormat(
732061da546Spatrick "unable to find a NULL terminated string at 0x%" PRIx64
733061da546Spatrick ". Consider increasing the maximum read length.\n",
734061da546Spatrick data_addr);
735061da546Spatrick --read;
736061da546Spatrick break_on_no_NULL = true;
737061da546Spatrick } else
738061da546Spatrick ++read; // account for final NULL byte
739061da546Spatrick
740061da546Spatrick memcpy(data_ptr, &buffer[0], read);
741061da546Spatrick data_ptr += read;
742061da546Spatrick data_addr += read;
743061da546Spatrick bytes_read += read;
744061da546Spatrick item_count++; // if we break early we know we only read item_count
745061da546Spatrick // strings
746061da546Spatrick
747061da546Spatrick if (break_on_no_NULL)
748061da546Spatrick break;
749061da546Spatrick }
750061da546Spatrick data_sp =
751061da546Spatrick std::make_shared<DataBufferHeap>(data_sp->GetBytes(), bytes_read + 1);
752061da546Spatrick }
753061da546Spatrick
754061da546Spatrick m_next_addr = addr + bytes_read;
755061da546Spatrick m_prev_byte_size = bytes_read;
756061da546Spatrick m_prev_format_options = m_format_options;
757061da546Spatrick m_prev_memory_options = m_memory_options;
758061da546Spatrick m_prev_outfile_options = m_outfile_options;
759061da546Spatrick m_prev_varobj_options = m_varobj_options;
760*f6aab3d8Srobert m_prev_memory_tag_options = m_memory_tag_options;
761061da546Spatrick m_prev_compiler_type = compiler_type;
762061da546Spatrick
763061da546Spatrick std::unique_ptr<Stream> output_stream_storage;
764061da546Spatrick Stream *output_stream_p = nullptr;
765061da546Spatrick const FileSpec &outfile_spec =
766061da546Spatrick m_outfile_options.GetFile().GetCurrentValue();
767061da546Spatrick
768061da546Spatrick std::string path = outfile_spec.GetPath();
769061da546Spatrick if (outfile_spec) {
770061da546Spatrick
771be691f3bSpatrick File::OpenOptions open_options =
772*f6aab3d8Srobert File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate;
773061da546Spatrick const bool append = m_outfile_options.GetAppend().GetCurrentValue();
774be691f3bSpatrick open_options |=
775be691f3bSpatrick append ? File::eOpenOptionAppend : File::eOpenOptionTruncate;
776061da546Spatrick
777061da546Spatrick auto outfile = FileSystem::Instance().Open(outfile_spec, open_options);
778061da546Spatrick
779061da546Spatrick if (outfile) {
780061da546Spatrick auto outfile_stream_up =
781061da546Spatrick std::make_unique<StreamFile>(std::move(outfile.get()));
782061da546Spatrick if (m_memory_options.m_output_as_binary) {
783061da546Spatrick const size_t bytes_written =
784061da546Spatrick outfile_stream_up->Write(data_sp->GetBytes(), bytes_read);
785061da546Spatrick if (bytes_written > 0) {
786061da546Spatrick result.GetOutputStream().Printf(
787061da546Spatrick "%zi bytes %s to '%s'\n", bytes_written,
788061da546Spatrick append ? "appended" : "written", path.c_str());
789061da546Spatrick return true;
790061da546Spatrick } else {
791061da546Spatrick result.AppendErrorWithFormat("Failed to write %" PRIu64
792061da546Spatrick " bytes to '%s'.\n",
793061da546Spatrick (uint64_t)bytes_read, path.c_str());
794061da546Spatrick return false;
795061da546Spatrick }
796061da546Spatrick } else {
797061da546Spatrick // We are going to write ASCII to the file just point the
798061da546Spatrick // output_stream to our outfile_stream...
799061da546Spatrick output_stream_storage = std::move(outfile_stream_up);
800061da546Spatrick output_stream_p = output_stream_storage.get();
801061da546Spatrick }
802061da546Spatrick } else {
803061da546Spatrick result.AppendErrorWithFormat("Failed to open file '%s' for %s:\n",
804061da546Spatrick path.c_str(), append ? "append" : "write");
805061da546Spatrick
806061da546Spatrick result.AppendError(llvm::toString(outfile.takeError()));
807061da546Spatrick return false;
808061da546Spatrick }
809061da546Spatrick } else {
810061da546Spatrick output_stream_p = &result.GetOutputStream();
811061da546Spatrick }
812061da546Spatrick
813061da546Spatrick ExecutionContextScope *exe_scope = m_exe_ctx.GetBestExecutionContextScope();
814061da546Spatrick if (compiler_type.GetOpaqueQualType()) {
815061da546Spatrick for (uint32_t i = 0; i < item_count; ++i) {
816061da546Spatrick addr_t item_addr = addr + (i * item_byte_size);
817061da546Spatrick Address address(item_addr);
818061da546Spatrick StreamString name_strm;
819061da546Spatrick name_strm.Printf("0x%" PRIx64, item_addr);
820061da546Spatrick ValueObjectSP valobj_sp(ValueObjectMemory::Create(
821061da546Spatrick exe_scope, name_strm.GetString(), address, compiler_type));
822061da546Spatrick if (valobj_sp) {
823061da546Spatrick Format format = m_format_options.GetFormat();
824061da546Spatrick if (format != eFormatDefault)
825061da546Spatrick valobj_sp->SetFormat(format);
826061da546Spatrick
827061da546Spatrick DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
828061da546Spatrick eLanguageRuntimeDescriptionDisplayVerbosityFull, format));
829061da546Spatrick
830061da546Spatrick valobj_sp->Dump(*output_stream_p, options);
831061da546Spatrick } else {
832061da546Spatrick result.AppendErrorWithFormat(
833061da546Spatrick "failed to create a value object for: (%s) %s\n",
834061da546Spatrick view_as_type_cstr, name_strm.GetData());
835061da546Spatrick return false;
836061da546Spatrick }
837061da546Spatrick }
838061da546Spatrick return true;
839061da546Spatrick }
840061da546Spatrick
841061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
842061da546Spatrick DataExtractor data(data_sp, target->GetArchitecture().GetByteOrder(),
843061da546Spatrick target->GetArchitecture().GetAddressByteSize(),
844061da546Spatrick target->GetArchitecture().GetDataByteSize());
845061da546Spatrick
846061da546Spatrick Format format = m_format_options.GetFormat();
847061da546Spatrick if (((format == eFormatChar) || (format == eFormatCharPrintable)) &&
848061da546Spatrick (item_byte_size != 1)) {
849061da546Spatrick // if a count was not passed, or it is 1
850061da546Spatrick if (!m_format_options.GetCountValue().OptionWasSet() || item_count == 1) {
851061da546Spatrick // this turns requests such as
852061da546Spatrick // memory read -fc -s10 -c1 *charPtrPtr
853061da546Spatrick // which make no sense (what is a char of size 10?) into a request for
854061da546Spatrick // fetching 10 chars of size 1 from the same memory location
855061da546Spatrick format = eFormatCharArray;
856061da546Spatrick item_count = item_byte_size;
857061da546Spatrick item_byte_size = 1;
858061da546Spatrick } else {
859061da546Spatrick // here we passed a count, and it was not 1 so we have a byte_size and
860061da546Spatrick // a count we could well multiply those, but instead let's just fail
861061da546Spatrick result.AppendErrorWithFormat(
862061da546Spatrick "reading memory as characters of size %" PRIu64 " is not supported",
863061da546Spatrick (uint64_t)item_byte_size);
864061da546Spatrick return false;
865061da546Spatrick }
866061da546Spatrick }
867061da546Spatrick
868061da546Spatrick assert(output_stream_p);
869061da546Spatrick size_t bytes_dumped = DumpDataExtractor(
870061da546Spatrick data, output_stream_p, 0, format, item_byte_size, item_count,
871061da546Spatrick num_per_line / target->GetArchitecture().GetDataByteSize(), addr, 0, 0,
872*f6aab3d8Srobert exe_scope, m_memory_tag_options.GetShowTags().GetCurrentValue());
873061da546Spatrick m_next_addr = addr + bytes_dumped;
874061da546Spatrick output_stream_p->EOL();
875061da546Spatrick return true;
876061da546Spatrick }
877061da546Spatrick
878061da546Spatrick OptionGroupOptions m_option_group;
879061da546Spatrick OptionGroupFormat m_format_options;
880061da546Spatrick OptionGroupReadMemory m_memory_options;
881061da546Spatrick OptionGroupOutputFile m_outfile_options;
882061da546Spatrick OptionGroupValueObjectDisplay m_varobj_options;
883*f6aab3d8Srobert OptionGroupMemoryTag m_memory_tag_options;
884*f6aab3d8Srobert lldb::addr_t m_next_addr = LLDB_INVALID_ADDRESS;
885*f6aab3d8Srobert lldb::addr_t m_prev_byte_size = 0;
886061da546Spatrick OptionGroupFormat m_prev_format_options;
887061da546Spatrick OptionGroupReadMemory m_prev_memory_options;
888061da546Spatrick OptionGroupOutputFile m_prev_outfile_options;
889061da546Spatrick OptionGroupValueObjectDisplay m_prev_varobj_options;
890*f6aab3d8Srobert OptionGroupMemoryTag m_prev_memory_tag_options;
891061da546Spatrick CompilerType m_prev_compiler_type;
892061da546Spatrick };
893061da546Spatrick
894061da546Spatrick #define LLDB_OPTIONS_memory_find
895061da546Spatrick #include "CommandOptions.inc"
896061da546Spatrick
897061da546Spatrick // Find the specified data in memory
898061da546Spatrick class CommandObjectMemoryFind : public CommandObjectParsed {
899061da546Spatrick public:
900061da546Spatrick class OptionGroupFindMemory : public OptionGroup {
901061da546Spatrick public:
OptionGroupFindMemory()902*f6aab3d8Srobert OptionGroupFindMemory() : m_count(1), m_offset(0) {}
903061da546Spatrick
904061da546Spatrick ~OptionGroupFindMemory() override = default;
905061da546Spatrick
GetDefinitions()906061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
907*f6aab3d8Srobert return llvm::ArrayRef(g_memory_find_options);
908061da546Spatrick }
909061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_value,ExecutionContext * execution_context)910061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
911061da546Spatrick ExecutionContext *execution_context) override {
912061da546Spatrick Status error;
913061da546Spatrick const int short_option = g_memory_find_options[option_idx].short_option;
914061da546Spatrick
915061da546Spatrick switch (short_option) {
916061da546Spatrick case 'e':
917061da546Spatrick m_expr.SetValueFromString(option_value);
918061da546Spatrick break;
919061da546Spatrick
920061da546Spatrick case 's':
921061da546Spatrick m_string.SetValueFromString(option_value);
922061da546Spatrick break;
923061da546Spatrick
924061da546Spatrick case 'c':
925061da546Spatrick if (m_count.SetValueFromString(option_value).Fail())
926061da546Spatrick error.SetErrorString("unrecognized value for count");
927061da546Spatrick break;
928061da546Spatrick
929061da546Spatrick case 'o':
930061da546Spatrick if (m_offset.SetValueFromString(option_value).Fail())
931061da546Spatrick error.SetErrorString("unrecognized value for dump-offset");
932061da546Spatrick break;
933061da546Spatrick
934061da546Spatrick default:
935061da546Spatrick llvm_unreachable("Unimplemented option");
936061da546Spatrick }
937061da546Spatrick return error;
938061da546Spatrick }
939061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)940061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
941061da546Spatrick m_expr.Clear();
942061da546Spatrick m_string.Clear();
943061da546Spatrick m_count.Clear();
944061da546Spatrick }
945061da546Spatrick
946061da546Spatrick OptionValueString m_expr;
947061da546Spatrick OptionValueString m_string;
948061da546Spatrick OptionValueUInt64 m_count;
949061da546Spatrick OptionValueUInt64 m_offset;
950061da546Spatrick };
951061da546Spatrick
CommandObjectMemoryFind(CommandInterpreter & interpreter)952061da546Spatrick CommandObjectMemoryFind(CommandInterpreter &interpreter)
953061da546Spatrick : CommandObjectParsed(
954061da546Spatrick interpreter, "memory find",
955061da546Spatrick "Find a value in the memory of the current target process.",
956*f6aab3d8Srobert nullptr, eCommandRequiresProcess | eCommandProcessMustBeLaunched) {
957061da546Spatrick CommandArgumentEntry arg1;
958061da546Spatrick CommandArgumentEntry arg2;
959061da546Spatrick CommandArgumentData addr_arg;
960061da546Spatrick CommandArgumentData value_arg;
961061da546Spatrick
962061da546Spatrick // Define the first (and only) variant of this arg.
963061da546Spatrick addr_arg.arg_type = eArgTypeAddressOrExpression;
964061da546Spatrick addr_arg.arg_repetition = eArgRepeatPlain;
965061da546Spatrick
966061da546Spatrick // There is only one variant this argument could be; put it into the
967061da546Spatrick // argument entry.
968061da546Spatrick arg1.push_back(addr_arg);
969061da546Spatrick
970061da546Spatrick // Define the first (and only) variant of this arg.
971061da546Spatrick value_arg.arg_type = eArgTypeAddressOrExpression;
972061da546Spatrick value_arg.arg_repetition = eArgRepeatPlain;
973061da546Spatrick
974061da546Spatrick // There is only one variant this argument could be; put it into the
975061da546Spatrick // argument entry.
976061da546Spatrick arg2.push_back(value_arg);
977061da546Spatrick
978061da546Spatrick // Push the data for the first argument into the m_arguments vector.
979061da546Spatrick m_arguments.push_back(arg1);
980061da546Spatrick m_arguments.push_back(arg2);
981061da546Spatrick
982061da546Spatrick m_option_group.Append(&m_memory_options);
983*f6aab3d8Srobert m_option_group.Append(&m_memory_tag_options, LLDB_OPT_SET_ALL,
984*f6aab3d8Srobert LLDB_OPT_SET_ALL);
985061da546Spatrick m_option_group.Finalize();
986061da546Spatrick }
987061da546Spatrick
988061da546Spatrick ~CommandObjectMemoryFind() override = default;
989061da546Spatrick
GetOptions()990061da546Spatrick Options *GetOptions() override { return &m_option_group; }
991061da546Spatrick
992061da546Spatrick protected:
993061da546Spatrick class ProcessMemoryIterator {
994061da546Spatrick public:
ProcessMemoryIterator(ProcessSP process_sp,lldb::addr_t base)995061da546Spatrick ProcessMemoryIterator(ProcessSP process_sp, lldb::addr_t base)
996*f6aab3d8Srobert : m_process_sp(process_sp), m_base_addr(base) {
997061da546Spatrick lldbassert(process_sp.get() != nullptr);
998061da546Spatrick }
999061da546Spatrick
IsValid()1000061da546Spatrick bool IsValid() { return m_is_valid; }
1001061da546Spatrick
operator [](lldb::addr_t offset)1002061da546Spatrick uint8_t operator[](lldb::addr_t offset) {
1003061da546Spatrick if (!IsValid())
1004061da546Spatrick return 0;
1005061da546Spatrick
1006061da546Spatrick uint8_t retval = 0;
1007061da546Spatrick Status error;
1008061da546Spatrick if (0 ==
1009061da546Spatrick m_process_sp->ReadMemory(m_base_addr + offset, &retval, 1, error)) {
1010061da546Spatrick m_is_valid = false;
1011061da546Spatrick return 0;
1012061da546Spatrick }
1013061da546Spatrick
1014061da546Spatrick return retval;
1015061da546Spatrick }
1016061da546Spatrick
1017061da546Spatrick private:
1018061da546Spatrick ProcessSP m_process_sp;
1019061da546Spatrick lldb::addr_t m_base_addr;
1020*f6aab3d8Srobert bool m_is_valid = true;
1021061da546Spatrick };
DoExecute(Args & command,CommandReturnObject & result)1022061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
1023061da546Spatrick // No need to check "process" for validity as eCommandRequiresProcess
1024061da546Spatrick // ensures it is valid
1025061da546Spatrick Process *process = m_exe_ctx.GetProcessPtr();
1026061da546Spatrick
1027061da546Spatrick const size_t argc = command.GetArgumentCount();
1028061da546Spatrick
1029061da546Spatrick if (argc != 2) {
1030061da546Spatrick result.AppendError("two addresses needed for memory find");
1031061da546Spatrick return false;
1032061da546Spatrick }
1033061da546Spatrick
1034061da546Spatrick Status error;
1035061da546Spatrick lldb::addr_t low_addr = OptionArgParser::ToAddress(
1036061da546Spatrick &m_exe_ctx, command[0].ref(), LLDB_INVALID_ADDRESS, &error);
1037061da546Spatrick if (low_addr == LLDB_INVALID_ADDRESS || error.Fail()) {
1038061da546Spatrick result.AppendError("invalid low address");
1039061da546Spatrick return false;
1040061da546Spatrick }
1041061da546Spatrick lldb::addr_t high_addr = OptionArgParser::ToAddress(
1042061da546Spatrick &m_exe_ctx, command[1].ref(), LLDB_INVALID_ADDRESS, &error);
1043061da546Spatrick if (high_addr == LLDB_INVALID_ADDRESS || error.Fail()) {
1044061da546Spatrick result.AppendError("invalid high address");
1045061da546Spatrick return false;
1046061da546Spatrick }
1047061da546Spatrick
1048*f6aab3d8Srobert ABISP abi = m_exe_ctx.GetProcessPtr()->GetABI();
1049*f6aab3d8Srobert if (abi) {
1050*f6aab3d8Srobert low_addr = abi->FixDataAddress(low_addr);
1051*f6aab3d8Srobert high_addr = abi->FixDataAddress(high_addr);
1052*f6aab3d8Srobert }
1053*f6aab3d8Srobert
1054061da546Spatrick if (high_addr <= low_addr) {
1055061da546Spatrick result.AppendError(
1056061da546Spatrick "starting address must be smaller than ending address");
1057061da546Spatrick return false;
1058061da546Spatrick }
1059061da546Spatrick
1060061da546Spatrick lldb::addr_t found_location = LLDB_INVALID_ADDRESS;
1061061da546Spatrick
1062061da546Spatrick DataBufferHeap buffer;
1063061da546Spatrick
1064*f6aab3d8Srobert if (m_memory_options.m_string.OptionWasSet()) {
1065*f6aab3d8Srobert llvm::StringRef str = m_memory_options.m_string.GetStringValue();
1066*f6aab3d8Srobert if (str.empty()) {
1067*f6aab3d8Srobert result.AppendError("search string must have non-zero length.");
1068*f6aab3d8Srobert return false;
1069*f6aab3d8Srobert }
1070*f6aab3d8Srobert buffer.CopyData(str);
1071*f6aab3d8Srobert } else if (m_memory_options.m_expr.OptionWasSet()) {
1072061da546Spatrick StackFrame *frame = m_exe_ctx.GetFramePtr();
1073061da546Spatrick ValueObjectSP result_sp;
1074061da546Spatrick if ((eExpressionCompleted ==
1075061da546Spatrick process->GetTarget().EvaluateExpression(
1076061da546Spatrick m_memory_options.m_expr.GetStringValue(), frame, result_sp)) &&
1077061da546Spatrick result_sp) {
1078061da546Spatrick uint64_t value = result_sp->GetValueAsUnsigned(0);
1079*f6aab3d8Srobert std::optional<uint64_t> size =
1080061da546Spatrick result_sp->GetCompilerType().GetByteSize(nullptr);
1081061da546Spatrick if (!size)
1082061da546Spatrick return false;
1083061da546Spatrick switch (*size) {
1084061da546Spatrick case 1: {
1085061da546Spatrick uint8_t byte = (uint8_t)value;
1086061da546Spatrick buffer.CopyData(&byte, 1);
1087061da546Spatrick } break;
1088061da546Spatrick case 2: {
1089061da546Spatrick uint16_t word = (uint16_t)value;
1090061da546Spatrick buffer.CopyData(&word, 2);
1091061da546Spatrick } break;
1092061da546Spatrick case 4: {
1093061da546Spatrick uint32_t lword = (uint32_t)value;
1094061da546Spatrick buffer.CopyData(&lword, 4);
1095061da546Spatrick } break;
1096061da546Spatrick case 8: {
1097061da546Spatrick buffer.CopyData(&value, 8);
1098061da546Spatrick } break;
1099061da546Spatrick case 3:
1100061da546Spatrick case 5:
1101061da546Spatrick case 6:
1102061da546Spatrick case 7:
1103061da546Spatrick result.AppendError("unknown type. pass a string instead");
1104061da546Spatrick return false;
1105061da546Spatrick default:
1106061da546Spatrick result.AppendError(
1107061da546Spatrick "result size larger than 8 bytes. pass a string instead");
1108061da546Spatrick return false;
1109061da546Spatrick }
1110061da546Spatrick } else {
1111061da546Spatrick result.AppendError(
1112061da546Spatrick "expression evaluation failed. pass a string instead");
1113061da546Spatrick return false;
1114061da546Spatrick }
1115061da546Spatrick } else {
1116061da546Spatrick result.AppendError(
1117061da546Spatrick "please pass either a block of text, or an expression to evaluate.");
1118061da546Spatrick return false;
1119061da546Spatrick }
1120061da546Spatrick
1121061da546Spatrick size_t count = m_memory_options.m_count.GetCurrentValue();
1122061da546Spatrick found_location = low_addr;
1123061da546Spatrick bool ever_found = false;
1124061da546Spatrick while (count) {
1125061da546Spatrick found_location = FastSearch(found_location, high_addr, buffer.GetBytes(),
1126061da546Spatrick buffer.GetByteSize());
1127061da546Spatrick if (found_location == LLDB_INVALID_ADDRESS) {
1128061da546Spatrick if (!ever_found) {
1129061da546Spatrick result.AppendMessage("data not found within the range.\n");
1130061da546Spatrick result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
1131061da546Spatrick } else
1132061da546Spatrick result.AppendMessage("no more matches within the range.\n");
1133061da546Spatrick break;
1134061da546Spatrick }
1135061da546Spatrick result.AppendMessageWithFormat("data found at location: 0x%" PRIx64 "\n",
1136061da546Spatrick found_location);
1137061da546Spatrick
1138061da546Spatrick DataBufferHeap dumpbuffer(32, 0);
1139061da546Spatrick process->ReadMemory(
1140061da546Spatrick found_location + m_memory_options.m_offset.GetCurrentValue(),
1141061da546Spatrick dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(), error);
1142061da546Spatrick if (!error.Fail()) {
1143061da546Spatrick DataExtractor data(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(),
1144061da546Spatrick process->GetByteOrder(),
1145061da546Spatrick process->GetAddressByteSize());
1146061da546Spatrick DumpDataExtractor(
1147061da546Spatrick data, &result.GetOutputStream(), 0, lldb::eFormatBytesWithASCII, 1,
1148061da546Spatrick dumpbuffer.GetByteSize(), 16,
1149*f6aab3d8Srobert found_location + m_memory_options.m_offset.GetCurrentValue(), 0, 0,
1150*f6aab3d8Srobert m_exe_ctx.GetBestExecutionContextScope(),
1151*f6aab3d8Srobert m_memory_tag_options.GetShowTags().GetCurrentValue());
1152061da546Spatrick result.GetOutputStream().EOL();
1153061da546Spatrick }
1154061da546Spatrick
1155061da546Spatrick --count;
1156061da546Spatrick found_location++;
1157061da546Spatrick ever_found = true;
1158061da546Spatrick }
1159061da546Spatrick
1160061da546Spatrick result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
1161061da546Spatrick return true;
1162061da546Spatrick }
1163061da546Spatrick
FastSearch(lldb::addr_t low,lldb::addr_t high,uint8_t * buffer,size_t buffer_size)1164061da546Spatrick lldb::addr_t FastSearch(lldb::addr_t low, lldb::addr_t high, uint8_t *buffer,
1165061da546Spatrick size_t buffer_size) {
1166061da546Spatrick const size_t region_size = high - low;
1167061da546Spatrick
1168061da546Spatrick if (region_size < buffer_size)
1169061da546Spatrick return LLDB_INVALID_ADDRESS;
1170061da546Spatrick
1171061da546Spatrick std::vector<size_t> bad_char_heuristic(256, buffer_size);
1172061da546Spatrick ProcessSP process_sp = m_exe_ctx.GetProcessSP();
1173061da546Spatrick ProcessMemoryIterator iterator(process_sp, low);
1174061da546Spatrick
1175061da546Spatrick for (size_t idx = 0; idx < buffer_size - 1; idx++) {
1176061da546Spatrick decltype(bad_char_heuristic)::size_type bcu_idx = buffer[idx];
1177061da546Spatrick bad_char_heuristic[bcu_idx] = buffer_size - idx - 1;
1178061da546Spatrick }
1179061da546Spatrick for (size_t s = 0; s <= (region_size - buffer_size);) {
1180061da546Spatrick int64_t j = buffer_size - 1;
1181061da546Spatrick while (j >= 0 && buffer[j] == iterator[s + j])
1182061da546Spatrick j--;
1183061da546Spatrick if (j < 0)
1184061da546Spatrick return low + s;
1185061da546Spatrick else
1186061da546Spatrick s += bad_char_heuristic[iterator[s + buffer_size - 1]];
1187061da546Spatrick }
1188061da546Spatrick
1189061da546Spatrick return LLDB_INVALID_ADDRESS;
1190061da546Spatrick }
1191061da546Spatrick
1192061da546Spatrick OptionGroupOptions m_option_group;
1193061da546Spatrick OptionGroupFindMemory m_memory_options;
1194*f6aab3d8Srobert OptionGroupMemoryTag m_memory_tag_options;
1195061da546Spatrick };
1196061da546Spatrick
1197061da546Spatrick #define LLDB_OPTIONS_memory_write
1198061da546Spatrick #include "CommandOptions.inc"
1199061da546Spatrick
1200061da546Spatrick // Write memory to the inferior process
1201061da546Spatrick class CommandObjectMemoryWrite : public CommandObjectParsed {
1202061da546Spatrick public:
1203061da546Spatrick class OptionGroupWriteMemory : public OptionGroup {
1204061da546Spatrick public:
1205*f6aab3d8Srobert OptionGroupWriteMemory() = default;
1206061da546Spatrick
1207061da546Spatrick ~OptionGroupWriteMemory() override = default;
1208061da546Spatrick
GetDefinitions()1209061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1210*f6aab3d8Srobert return llvm::ArrayRef(g_memory_write_options);
1211061da546Spatrick }
1212061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_value,ExecutionContext * execution_context)1213061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
1214061da546Spatrick ExecutionContext *execution_context) override {
1215061da546Spatrick Status error;
1216061da546Spatrick const int short_option = g_memory_write_options[option_idx].short_option;
1217061da546Spatrick
1218061da546Spatrick switch (short_option) {
1219061da546Spatrick case 'i':
1220061da546Spatrick m_infile.SetFile(option_value, FileSpec::Style::native);
1221061da546Spatrick FileSystem::Instance().Resolve(m_infile);
1222061da546Spatrick if (!FileSystem::Instance().Exists(m_infile)) {
1223061da546Spatrick m_infile.Clear();
1224061da546Spatrick error.SetErrorStringWithFormat("input file does not exist: '%s'",
1225061da546Spatrick option_value.str().c_str());
1226061da546Spatrick }
1227061da546Spatrick break;
1228061da546Spatrick
1229061da546Spatrick case 'o': {
1230061da546Spatrick if (option_value.getAsInteger(0, m_infile_offset)) {
1231061da546Spatrick m_infile_offset = 0;
1232061da546Spatrick error.SetErrorStringWithFormat("invalid offset string '%s'",
1233061da546Spatrick option_value.str().c_str());
1234061da546Spatrick }
1235061da546Spatrick } break;
1236061da546Spatrick
1237061da546Spatrick default:
1238061da546Spatrick llvm_unreachable("Unimplemented option");
1239061da546Spatrick }
1240061da546Spatrick return error;
1241061da546Spatrick }
1242061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)1243061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
1244061da546Spatrick m_infile.Clear();
1245061da546Spatrick m_infile_offset = 0;
1246061da546Spatrick }
1247061da546Spatrick
1248061da546Spatrick FileSpec m_infile;
1249061da546Spatrick off_t m_infile_offset;
1250061da546Spatrick };
1251061da546Spatrick
CommandObjectMemoryWrite(CommandInterpreter & interpreter)1252061da546Spatrick CommandObjectMemoryWrite(CommandInterpreter &interpreter)
1253061da546Spatrick : CommandObjectParsed(
1254061da546Spatrick interpreter, "memory write",
1255061da546Spatrick "Write to the memory of the current target process.", nullptr,
1256061da546Spatrick eCommandRequiresProcess | eCommandProcessMustBeLaunched),
1257*f6aab3d8Srobert m_format_options(
1258*f6aab3d8Srobert eFormatBytes, 1, UINT64_MAX,
1259*f6aab3d8Srobert {std::make_tuple(
1260*f6aab3d8Srobert eArgTypeFormat,
1261*f6aab3d8Srobert "The format to use for each of the value to be written."),
1262*f6aab3d8Srobert std::make_tuple(eArgTypeByteSize,
1263*f6aab3d8Srobert "The size in bytes to write from input file or "
1264*f6aab3d8Srobert "each value.")}) {
1265061da546Spatrick CommandArgumentEntry arg1;
1266061da546Spatrick CommandArgumentEntry arg2;
1267061da546Spatrick CommandArgumentData addr_arg;
1268061da546Spatrick CommandArgumentData value_arg;
1269061da546Spatrick
1270061da546Spatrick // Define the first (and only) variant of this arg.
1271061da546Spatrick addr_arg.arg_type = eArgTypeAddress;
1272061da546Spatrick addr_arg.arg_repetition = eArgRepeatPlain;
1273061da546Spatrick
1274061da546Spatrick // There is only one variant this argument could be; put it into the
1275061da546Spatrick // argument entry.
1276061da546Spatrick arg1.push_back(addr_arg);
1277061da546Spatrick
1278061da546Spatrick // Define the first (and only) variant of this arg.
1279061da546Spatrick value_arg.arg_type = eArgTypeValue;
1280061da546Spatrick value_arg.arg_repetition = eArgRepeatPlus;
1281*f6aab3d8Srobert value_arg.arg_opt_set_association = LLDB_OPT_SET_1;
1282061da546Spatrick
1283061da546Spatrick // There is only one variant this argument could be; put it into the
1284061da546Spatrick // argument entry.
1285061da546Spatrick arg2.push_back(value_arg);
1286061da546Spatrick
1287061da546Spatrick // Push the data for the first argument into the m_arguments vector.
1288061da546Spatrick m_arguments.push_back(arg1);
1289061da546Spatrick m_arguments.push_back(arg2);
1290061da546Spatrick
1291061da546Spatrick m_option_group.Append(&m_format_options,
1292061da546Spatrick OptionGroupFormat::OPTION_GROUP_FORMAT,
1293061da546Spatrick LLDB_OPT_SET_1);
1294061da546Spatrick m_option_group.Append(&m_format_options,
1295061da546Spatrick OptionGroupFormat::OPTION_GROUP_SIZE,
1296061da546Spatrick LLDB_OPT_SET_1 | LLDB_OPT_SET_2);
1297061da546Spatrick m_option_group.Append(&m_memory_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_2);
1298061da546Spatrick m_option_group.Finalize();
1299061da546Spatrick }
1300061da546Spatrick
1301061da546Spatrick ~CommandObjectMemoryWrite() override = default;
1302061da546Spatrick
GetOptions()1303061da546Spatrick Options *GetOptions() override { return &m_option_group; }
1304061da546Spatrick
1305061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1306061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
1307061da546Spatrick // No need to check "process" for validity as eCommandRequiresProcess
1308061da546Spatrick // ensures it is valid
1309061da546Spatrick Process *process = m_exe_ctx.GetProcessPtr();
1310061da546Spatrick
1311061da546Spatrick const size_t argc = command.GetArgumentCount();
1312061da546Spatrick
1313061da546Spatrick if (m_memory_options.m_infile) {
1314061da546Spatrick if (argc < 1) {
1315061da546Spatrick result.AppendErrorWithFormat(
1316061da546Spatrick "%s takes a destination address when writing file contents.\n",
1317061da546Spatrick m_cmd_name.c_str());
1318061da546Spatrick return false;
1319061da546Spatrick }
1320*f6aab3d8Srobert if (argc > 1) {
1321*f6aab3d8Srobert result.AppendErrorWithFormat(
1322*f6aab3d8Srobert "%s takes only a destination address when writing file contents.\n",
1323*f6aab3d8Srobert m_cmd_name.c_str());
1324*f6aab3d8Srobert return false;
1325*f6aab3d8Srobert }
1326061da546Spatrick } else if (argc < 2) {
1327061da546Spatrick result.AppendErrorWithFormat(
1328061da546Spatrick "%s takes a destination address and at least one value.\n",
1329061da546Spatrick m_cmd_name.c_str());
1330061da546Spatrick return false;
1331061da546Spatrick }
1332061da546Spatrick
1333061da546Spatrick StreamString buffer(
1334061da546Spatrick Stream::eBinary,
1335061da546Spatrick process->GetTarget().GetArchitecture().GetAddressByteSize(),
1336061da546Spatrick process->GetTarget().GetArchitecture().GetByteOrder());
1337061da546Spatrick
1338061da546Spatrick OptionValueUInt64 &byte_size_value = m_format_options.GetByteSizeValue();
1339061da546Spatrick size_t item_byte_size = byte_size_value.GetCurrentValue();
1340061da546Spatrick
1341061da546Spatrick Status error;
1342061da546Spatrick lldb::addr_t addr = OptionArgParser::ToAddress(
1343061da546Spatrick &m_exe_ctx, command[0].ref(), LLDB_INVALID_ADDRESS, &error);
1344061da546Spatrick
1345061da546Spatrick if (addr == LLDB_INVALID_ADDRESS) {
1346061da546Spatrick result.AppendError("invalid address expression\n");
1347061da546Spatrick result.AppendError(error.AsCString());
1348061da546Spatrick return false;
1349061da546Spatrick }
1350061da546Spatrick
1351061da546Spatrick if (m_memory_options.m_infile) {
1352061da546Spatrick size_t length = SIZE_MAX;
1353061da546Spatrick if (item_byte_size > 1)
1354061da546Spatrick length = item_byte_size;
1355061da546Spatrick auto data_sp = FileSystem::Instance().CreateDataBuffer(
1356061da546Spatrick m_memory_options.m_infile.GetPath(), length,
1357061da546Spatrick m_memory_options.m_infile_offset);
1358061da546Spatrick if (data_sp) {
1359061da546Spatrick length = data_sp->GetByteSize();
1360061da546Spatrick if (length > 0) {
1361061da546Spatrick Status error;
1362061da546Spatrick size_t bytes_written =
1363061da546Spatrick process->WriteMemory(addr, data_sp->GetBytes(), length, error);
1364061da546Spatrick
1365061da546Spatrick if (bytes_written == length) {
1366061da546Spatrick // All bytes written
1367061da546Spatrick result.GetOutputStream().Printf(
1368061da546Spatrick "%" PRIu64 " bytes were written to 0x%" PRIx64 "\n",
1369061da546Spatrick (uint64_t)bytes_written, addr);
1370061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
1371061da546Spatrick } else if (bytes_written > 0) {
1372061da546Spatrick // Some byte written
1373061da546Spatrick result.GetOutputStream().Printf(
1374061da546Spatrick "%" PRIu64 " bytes of %" PRIu64
1375061da546Spatrick " requested were written to 0x%" PRIx64 "\n",
1376061da546Spatrick (uint64_t)bytes_written, (uint64_t)length, addr);
1377061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
1378061da546Spatrick } else {
1379061da546Spatrick result.AppendErrorWithFormat("Memory write to 0x%" PRIx64
1380061da546Spatrick " failed: %s.\n",
1381061da546Spatrick addr, error.AsCString());
1382061da546Spatrick }
1383061da546Spatrick }
1384061da546Spatrick } else {
1385061da546Spatrick result.AppendErrorWithFormat("Unable to read contents of file.\n");
1386061da546Spatrick }
1387061da546Spatrick return result.Succeeded();
1388061da546Spatrick } else if (item_byte_size == 0) {
1389061da546Spatrick if (m_format_options.GetFormat() == eFormatPointer)
1390061da546Spatrick item_byte_size = buffer.GetAddressByteSize();
1391061da546Spatrick else
1392061da546Spatrick item_byte_size = 1;
1393061da546Spatrick }
1394061da546Spatrick
1395061da546Spatrick command.Shift(); // shift off the address argument
1396061da546Spatrick uint64_t uval64;
1397061da546Spatrick int64_t sval64;
1398061da546Spatrick bool success = false;
1399061da546Spatrick for (auto &entry : command) {
1400061da546Spatrick switch (m_format_options.GetFormat()) {
1401061da546Spatrick case kNumFormats:
1402061da546Spatrick case eFormatFloat: // TODO: add support for floats soon
1403061da546Spatrick case eFormatCharPrintable:
1404061da546Spatrick case eFormatBytesWithASCII:
1405061da546Spatrick case eFormatComplex:
1406061da546Spatrick case eFormatEnum:
1407061da546Spatrick case eFormatUnicode8:
1408061da546Spatrick case eFormatUnicode16:
1409061da546Spatrick case eFormatUnicode32:
1410061da546Spatrick case eFormatVectorOfChar:
1411061da546Spatrick case eFormatVectorOfSInt8:
1412061da546Spatrick case eFormatVectorOfUInt8:
1413061da546Spatrick case eFormatVectorOfSInt16:
1414061da546Spatrick case eFormatVectorOfUInt16:
1415061da546Spatrick case eFormatVectorOfSInt32:
1416061da546Spatrick case eFormatVectorOfUInt32:
1417061da546Spatrick case eFormatVectorOfSInt64:
1418061da546Spatrick case eFormatVectorOfUInt64:
1419061da546Spatrick case eFormatVectorOfFloat16:
1420061da546Spatrick case eFormatVectorOfFloat32:
1421061da546Spatrick case eFormatVectorOfFloat64:
1422061da546Spatrick case eFormatVectorOfUInt128:
1423061da546Spatrick case eFormatOSType:
1424061da546Spatrick case eFormatComplexInteger:
1425061da546Spatrick case eFormatAddressInfo:
1426061da546Spatrick case eFormatHexFloat:
1427061da546Spatrick case eFormatInstruction:
1428061da546Spatrick case eFormatVoid:
1429061da546Spatrick result.AppendError("unsupported format for writing memory");
1430061da546Spatrick return false;
1431061da546Spatrick
1432061da546Spatrick case eFormatDefault:
1433061da546Spatrick case eFormatBytes:
1434061da546Spatrick case eFormatHex:
1435061da546Spatrick case eFormatHexUppercase:
1436061da546Spatrick case eFormatPointer: {
1437061da546Spatrick // Decode hex bytes
1438061da546Spatrick // Be careful, getAsInteger with a radix of 16 rejects "0xab" so we
1439061da546Spatrick // have to special case that:
1440061da546Spatrick bool success = false;
1441061da546Spatrick if (entry.ref().startswith("0x"))
1442061da546Spatrick success = !entry.ref().getAsInteger(0, uval64);
1443061da546Spatrick if (!success)
1444061da546Spatrick success = !entry.ref().getAsInteger(16, uval64);
1445061da546Spatrick if (!success) {
1446061da546Spatrick result.AppendErrorWithFormat(
1447061da546Spatrick "'%s' is not a valid hex string value.\n", entry.c_str());
1448061da546Spatrick return false;
1449be691f3bSpatrick } else if (!llvm::isUIntN(item_byte_size * 8, uval64)) {
1450061da546Spatrick result.AppendErrorWithFormat("Value 0x%" PRIx64
1451061da546Spatrick " is too large to fit in a %" PRIu64
1452061da546Spatrick " byte unsigned integer value.\n",
1453061da546Spatrick uval64, (uint64_t)item_byte_size);
1454061da546Spatrick return false;
1455061da546Spatrick }
1456061da546Spatrick buffer.PutMaxHex64(uval64, item_byte_size);
1457061da546Spatrick break;
1458061da546Spatrick }
1459061da546Spatrick case eFormatBoolean:
1460061da546Spatrick uval64 = OptionArgParser::ToBoolean(entry.ref(), false, &success);
1461061da546Spatrick if (!success) {
1462061da546Spatrick result.AppendErrorWithFormat(
1463061da546Spatrick "'%s' is not a valid boolean string value.\n", entry.c_str());
1464061da546Spatrick return false;
1465061da546Spatrick }
1466061da546Spatrick buffer.PutMaxHex64(uval64, item_byte_size);
1467061da546Spatrick break;
1468061da546Spatrick
1469061da546Spatrick case eFormatBinary:
1470061da546Spatrick if (entry.ref().getAsInteger(2, uval64)) {
1471061da546Spatrick result.AppendErrorWithFormat(
1472061da546Spatrick "'%s' is not a valid binary string value.\n", entry.c_str());
1473061da546Spatrick return false;
1474be691f3bSpatrick } else if (!llvm::isUIntN(item_byte_size * 8, uval64)) {
1475061da546Spatrick result.AppendErrorWithFormat("Value 0x%" PRIx64
1476061da546Spatrick " is too large to fit in a %" PRIu64
1477061da546Spatrick " byte unsigned integer value.\n",
1478061da546Spatrick uval64, (uint64_t)item_byte_size);
1479061da546Spatrick return false;
1480061da546Spatrick }
1481061da546Spatrick buffer.PutMaxHex64(uval64, item_byte_size);
1482061da546Spatrick break;
1483061da546Spatrick
1484061da546Spatrick case eFormatCharArray:
1485061da546Spatrick case eFormatChar:
1486061da546Spatrick case eFormatCString: {
1487061da546Spatrick if (entry.ref().empty())
1488061da546Spatrick break;
1489061da546Spatrick
1490061da546Spatrick size_t len = entry.ref().size();
1491061da546Spatrick // Include the NULL for C strings...
1492061da546Spatrick if (m_format_options.GetFormat() == eFormatCString)
1493061da546Spatrick ++len;
1494061da546Spatrick Status error;
1495061da546Spatrick if (process->WriteMemory(addr, entry.c_str(), len, error) == len) {
1496061da546Spatrick addr += len;
1497061da546Spatrick } else {
1498061da546Spatrick result.AppendErrorWithFormat("Memory write to 0x%" PRIx64
1499061da546Spatrick " failed: %s.\n",
1500061da546Spatrick addr, error.AsCString());
1501061da546Spatrick return false;
1502061da546Spatrick }
1503061da546Spatrick break;
1504061da546Spatrick }
1505061da546Spatrick case eFormatDecimal:
1506061da546Spatrick if (entry.ref().getAsInteger(0, sval64)) {
1507061da546Spatrick result.AppendErrorWithFormat(
1508061da546Spatrick "'%s' is not a valid signed decimal value.\n", entry.c_str());
1509061da546Spatrick return false;
1510be691f3bSpatrick } else if (!llvm::isIntN(item_byte_size * 8, sval64)) {
1511061da546Spatrick result.AppendErrorWithFormat(
1512061da546Spatrick "Value %" PRIi64 " is too large or small to fit in a %" PRIu64
1513061da546Spatrick " byte signed integer value.\n",
1514061da546Spatrick sval64, (uint64_t)item_byte_size);
1515061da546Spatrick return false;
1516061da546Spatrick }
1517061da546Spatrick buffer.PutMaxHex64(sval64, item_byte_size);
1518061da546Spatrick break;
1519061da546Spatrick
1520061da546Spatrick case eFormatUnsigned:
1521061da546Spatrick
1522be691f3bSpatrick if (entry.ref().getAsInteger(0, uval64)) {
1523061da546Spatrick result.AppendErrorWithFormat(
1524061da546Spatrick "'%s' is not a valid unsigned decimal string value.\n",
1525061da546Spatrick entry.c_str());
1526061da546Spatrick return false;
1527be691f3bSpatrick } else if (!llvm::isUIntN(item_byte_size * 8, uval64)) {
1528061da546Spatrick result.AppendErrorWithFormat("Value %" PRIu64
1529061da546Spatrick " is too large to fit in a %" PRIu64
1530061da546Spatrick " byte unsigned integer value.\n",
1531061da546Spatrick uval64, (uint64_t)item_byte_size);
1532061da546Spatrick return false;
1533061da546Spatrick }
1534061da546Spatrick buffer.PutMaxHex64(uval64, item_byte_size);
1535061da546Spatrick break;
1536061da546Spatrick
1537061da546Spatrick case eFormatOctal:
1538061da546Spatrick if (entry.ref().getAsInteger(8, uval64)) {
1539061da546Spatrick result.AppendErrorWithFormat(
1540061da546Spatrick "'%s' is not a valid octal string value.\n", entry.c_str());
1541061da546Spatrick return false;
1542be691f3bSpatrick } else if (!llvm::isUIntN(item_byte_size * 8, uval64)) {
1543061da546Spatrick result.AppendErrorWithFormat("Value %" PRIo64
1544061da546Spatrick " is too large to fit in a %" PRIu64
1545061da546Spatrick " byte unsigned integer value.\n",
1546061da546Spatrick uval64, (uint64_t)item_byte_size);
1547061da546Spatrick return false;
1548061da546Spatrick }
1549061da546Spatrick buffer.PutMaxHex64(uval64, item_byte_size);
1550061da546Spatrick break;
1551061da546Spatrick }
1552061da546Spatrick }
1553061da546Spatrick
1554061da546Spatrick if (!buffer.GetString().empty()) {
1555061da546Spatrick Status error;
1556061da546Spatrick if (process->WriteMemory(addr, buffer.GetString().data(),
1557061da546Spatrick buffer.GetString().size(),
1558061da546Spatrick error) == buffer.GetString().size())
1559061da546Spatrick return true;
1560061da546Spatrick else {
1561061da546Spatrick result.AppendErrorWithFormat("Memory write to 0x%" PRIx64
1562061da546Spatrick " failed: %s.\n",
1563061da546Spatrick addr, error.AsCString());
1564061da546Spatrick return false;
1565061da546Spatrick }
1566061da546Spatrick }
1567061da546Spatrick return true;
1568061da546Spatrick }
1569061da546Spatrick
1570061da546Spatrick OptionGroupOptions m_option_group;
1571061da546Spatrick OptionGroupFormat m_format_options;
1572061da546Spatrick OptionGroupWriteMemory m_memory_options;
1573061da546Spatrick };
1574061da546Spatrick
1575061da546Spatrick // Get malloc/free history of a memory address.
1576061da546Spatrick class CommandObjectMemoryHistory : public CommandObjectParsed {
1577061da546Spatrick public:
CommandObjectMemoryHistory(CommandInterpreter & interpreter)1578061da546Spatrick CommandObjectMemoryHistory(CommandInterpreter &interpreter)
1579061da546Spatrick : CommandObjectParsed(interpreter, "memory history",
1580061da546Spatrick "Print recorded stack traces for "
1581061da546Spatrick "allocation/deallocation events "
1582061da546Spatrick "associated with an address.",
1583061da546Spatrick nullptr,
1584061da546Spatrick eCommandRequiresTarget | eCommandRequiresProcess |
1585061da546Spatrick eCommandProcessMustBePaused |
1586061da546Spatrick eCommandProcessMustBeLaunched) {
1587061da546Spatrick CommandArgumentEntry arg1;
1588061da546Spatrick CommandArgumentData addr_arg;
1589061da546Spatrick
1590061da546Spatrick // Define the first (and only) variant of this arg.
1591061da546Spatrick addr_arg.arg_type = eArgTypeAddress;
1592061da546Spatrick addr_arg.arg_repetition = eArgRepeatPlain;
1593061da546Spatrick
1594061da546Spatrick // There is only one variant this argument could be; put it into the
1595061da546Spatrick // argument entry.
1596061da546Spatrick arg1.push_back(addr_arg);
1597061da546Spatrick
1598061da546Spatrick // Push the data for the first argument into the m_arguments vector.
1599061da546Spatrick m_arguments.push_back(arg1);
1600061da546Spatrick }
1601061da546Spatrick
1602061da546Spatrick ~CommandObjectMemoryHistory() override = default;
1603061da546Spatrick
GetRepeatCommand(Args & current_command_args,uint32_t index)1604*f6aab3d8Srobert std::optional<std::string> GetRepeatCommand(Args ¤t_command_args,
1605061da546Spatrick uint32_t index) override {
1606*f6aab3d8Srobert return m_cmd_name;
1607061da546Spatrick }
1608061da546Spatrick
1609061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1610061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
1611061da546Spatrick const size_t argc = command.GetArgumentCount();
1612061da546Spatrick
1613061da546Spatrick if (argc == 0 || argc > 1) {
1614061da546Spatrick result.AppendErrorWithFormat("%s takes an address expression",
1615061da546Spatrick m_cmd_name.c_str());
1616061da546Spatrick return false;
1617061da546Spatrick }
1618061da546Spatrick
1619061da546Spatrick Status error;
1620061da546Spatrick lldb::addr_t addr = OptionArgParser::ToAddress(
1621061da546Spatrick &m_exe_ctx, command[0].ref(), LLDB_INVALID_ADDRESS, &error);
1622061da546Spatrick
1623061da546Spatrick if (addr == LLDB_INVALID_ADDRESS) {
1624061da546Spatrick result.AppendError("invalid address expression");
1625061da546Spatrick result.AppendError(error.AsCString());
1626061da546Spatrick return false;
1627061da546Spatrick }
1628061da546Spatrick
1629061da546Spatrick Stream *output_stream = &result.GetOutputStream();
1630061da546Spatrick
1631061da546Spatrick const ProcessSP &process_sp = m_exe_ctx.GetProcessSP();
1632061da546Spatrick const MemoryHistorySP &memory_history =
1633061da546Spatrick MemoryHistory::FindPlugin(process_sp);
1634061da546Spatrick
1635061da546Spatrick if (!memory_history) {
1636061da546Spatrick result.AppendError("no available memory history provider");
1637061da546Spatrick return false;
1638061da546Spatrick }
1639061da546Spatrick
1640061da546Spatrick HistoryThreads thread_list = memory_history->GetHistoryThreads(addr);
1641061da546Spatrick
1642061da546Spatrick const bool stop_format = false;
1643061da546Spatrick for (auto thread : thread_list) {
1644061da546Spatrick thread->GetStatus(*output_stream, 0, UINT32_MAX, 0, stop_format);
1645061da546Spatrick }
1646061da546Spatrick
1647061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
1648061da546Spatrick
1649061da546Spatrick return true;
1650061da546Spatrick }
1651061da546Spatrick };
1652061da546Spatrick
1653061da546Spatrick // CommandObjectMemoryRegion
1654061da546Spatrick #pragma mark CommandObjectMemoryRegion
1655061da546Spatrick
1656*f6aab3d8Srobert #define LLDB_OPTIONS_memory_region
1657*f6aab3d8Srobert #include "CommandOptions.inc"
1658*f6aab3d8Srobert
1659061da546Spatrick class CommandObjectMemoryRegion : public CommandObjectParsed {
1660061da546Spatrick public:
1661*f6aab3d8Srobert class OptionGroupMemoryRegion : public OptionGroup {
1662*f6aab3d8Srobert public:
OptionGroupMemoryRegion()1663*f6aab3d8Srobert OptionGroupMemoryRegion() : m_all(false, false) {}
1664*f6aab3d8Srobert
1665*f6aab3d8Srobert ~OptionGroupMemoryRegion() override = default;
1666*f6aab3d8Srobert
GetDefinitions()1667*f6aab3d8Srobert llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1668*f6aab3d8Srobert return llvm::ArrayRef(g_memory_region_options);
1669*f6aab3d8Srobert }
1670*f6aab3d8Srobert
SetOptionValue(uint32_t option_idx,llvm::StringRef option_value,ExecutionContext * execution_context)1671*f6aab3d8Srobert Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
1672*f6aab3d8Srobert ExecutionContext *execution_context) override {
1673*f6aab3d8Srobert Status status;
1674*f6aab3d8Srobert const int short_option = g_memory_region_options[option_idx].short_option;
1675*f6aab3d8Srobert
1676*f6aab3d8Srobert switch (short_option) {
1677*f6aab3d8Srobert case 'a':
1678*f6aab3d8Srobert m_all.SetCurrentValue(true);
1679*f6aab3d8Srobert m_all.SetOptionWasSet();
1680*f6aab3d8Srobert break;
1681*f6aab3d8Srobert default:
1682*f6aab3d8Srobert llvm_unreachable("Unimplemented option");
1683*f6aab3d8Srobert }
1684*f6aab3d8Srobert
1685*f6aab3d8Srobert return status;
1686*f6aab3d8Srobert }
1687*f6aab3d8Srobert
OptionParsingStarting(ExecutionContext * execution_context)1688*f6aab3d8Srobert void OptionParsingStarting(ExecutionContext *execution_context) override {
1689*f6aab3d8Srobert m_all.Clear();
1690*f6aab3d8Srobert }
1691*f6aab3d8Srobert
1692*f6aab3d8Srobert OptionValueBoolean m_all;
1693*f6aab3d8Srobert };
1694*f6aab3d8Srobert
CommandObjectMemoryRegion(CommandInterpreter & interpreter)1695061da546Spatrick CommandObjectMemoryRegion(CommandInterpreter &interpreter)
1696061da546Spatrick : CommandObjectParsed(interpreter, "memory region",
1697061da546Spatrick "Get information on the memory region containing "
1698061da546Spatrick "an address in the current target process.",
1699*f6aab3d8Srobert "memory region <address-expression> (or --all)",
1700061da546Spatrick eCommandRequiresProcess | eCommandTryTargetAPILock |
1701*f6aab3d8Srobert eCommandProcessMustBeLaunched) {
1702*f6aab3d8Srobert // Address in option set 1.
1703*f6aab3d8Srobert m_arguments.push_back(CommandArgumentEntry{CommandArgumentData(
1704*f6aab3d8Srobert eArgTypeAddressOrExpression, eArgRepeatPlain, LLDB_OPT_SET_1)});
1705*f6aab3d8Srobert // "--all" will go in option set 2.
1706*f6aab3d8Srobert m_option_group.Append(&m_memory_region_options);
1707*f6aab3d8Srobert m_option_group.Finalize();
1708*f6aab3d8Srobert }
1709061da546Spatrick
1710061da546Spatrick ~CommandObjectMemoryRegion() override = default;
1711061da546Spatrick
GetOptions()1712*f6aab3d8Srobert Options *GetOptions() override { return &m_option_group; }
1713*f6aab3d8Srobert
1714061da546Spatrick protected:
DumpRegion(CommandReturnObject & result,Target & target,const MemoryRegionInfo & range_info,lldb::addr_t load_addr)1715*f6aab3d8Srobert void DumpRegion(CommandReturnObject &result, Target &target,
1716*f6aab3d8Srobert const MemoryRegionInfo &range_info, lldb::addr_t load_addr) {
1717*f6aab3d8Srobert lldb_private::Address addr;
1718*f6aab3d8Srobert ConstString section_name;
1719*f6aab3d8Srobert if (target.ResolveLoadAddress(load_addr, addr)) {
1720*f6aab3d8Srobert SectionSP section_sp(addr.GetSection());
1721*f6aab3d8Srobert if (section_sp) {
1722*f6aab3d8Srobert // Got the top most section, not the deepest section
1723*f6aab3d8Srobert while (section_sp->GetParent())
1724*f6aab3d8Srobert section_sp = section_sp->GetParent();
1725*f6aab3d8Srobert section_name = section_sp->GetName();
1726*f6aab3d8Srobert }
1727*f6aab3d8Srobert }
1728*f6aab3d8Srobert
1729*f6aab3d8Srobert ConstString name = range_info.GetName();
1730*f6aab3d8Srobert result.AppendMessageWithFormatv(
1731*f6aab3d8Srobert "[{0:x16}-{1:x16}) {2:r}{3:w}{4:x}{5}{6}{7}{8}",
1732*f6aab3d8Srobert range_info.GetRange().GetRangeBase(),
1733*f6aab3d8Srobert range_info.GetRange().GetRangeEnd(), range_info.GetReadable(),
1734*f6aab3d8Srobert range_info.GetWritable(), range_info.GetExecutable(), name ? " " : "",
1735*f6aab3d8Srobert name, section_name ? " " : "", section_name);
1736*f6aab3d8Srobert MemoryRegionInfo::OptionalBool memory_tagged = range_info.GetMemoryTagged();
1737*f6aab3d8Srobert if (memory_tagged == MemoryRegionInfo::OptionalBool::eYes)
1738*f6aab3d8Srobert result.AppendMessage("memory tagging: enabled");
1739*f6aab3d8Srobert
1740*f6aab3d8Srobert const std::optional<std::vector<addr_t>> &dirty_page_list =
1741*f6aab3d8Srobert range_info.GetDirtyPageList();
1742*f6aab3d8Srobert if (dirty_page_list) {
1743*f6aab3d8Srobert const size_t page_count = dirty_page_list->size();
1744*f6aab3d8Srobert result.AppendMessageWithFormat(
1745*f6aab3d8Srobert "Modified memory (dirty) page list provided, %zu entries.\n",
1746*f6aab3d8Srobert page_count);
1747*f6aab3d8Srobert if (page_count > 0) {
1748*f6aab3d8Srobert bool print_comma = false;
1749*f6aab3d8Srobert result.AppendMessageWithFormat("Dirty pages: ");
1750*f6aab3d8Srobert for (size_t i = 0; i < page_count; i++) {
1751*f6aab3d8Srobert if (print_comma)
1752*f6aab3d8Srobert result.AppendMessageWithFormat(", ");
1753*f6aab3d8Srobert else
1754*f6aab3d8Srobert print_comma = true;
1755*f6aab3d8Srobert result.AppendMessageWithFormat("0x%" PRIx64, (*dirty_page_list)[i]);
1756*f6aab3d8Srobert }
1757*f6aab3d8Srobert result.AppendMessageWithFormat(".\n");
1758*f6aab3d8Srobert }
1759*f6aab3d8Srobert }
1760*f6aab3d8Srobert }
1761*f6aab3d8Srobert
DoExecute(Args & command,CommandReturnObject & result)1762061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
1763061da546Spatrick ProcessSP process_sp = m_exe_ctx.GetProcessSP();
1764be691f3bSpatrick if (!process_sp) {
1765be691f3bSpatrick m_prev_end_addr = LLDB_INVALID_ADDRESS;
1766be691f3bSpatrick result.AppendError("invalid process");
1767be691f3bSpatrick return false;
1768be691f3bSpatrick }
1769be691f3bSpatrick
1770061da546Spatrick Status error;
1771061da546Spatrick lldb::addr_t load_addr = m_prev_end_addr;
1772061da546Spatrick m_prev_end_addr = LLDB_INVALID_ADDRESS;
1773061da546Spatrick
1774061da546Spatrick const size_t argc = command.GetArgumentCount();
1775*f6aab3d8Srobert const lldb::ABISP &abi = process_sp->GetABI();
1776*f6aab3d8Srobert
1777*f6aab3d8Srobert if (argc == 1) {
1778*f6aab3d8Srobert if (m_memory_region_options.m_all) {
1779*f6aab3d8Srobert result.AppendError(
1780*f6aab3d8Srobert "The \"--all\" option cannot be used when an address "
1781*f6aab3d8Srobert "argument is given");
1782be691f3bSpatrick return false;
1783be691f3bSpatrick }
1784be691f3bSpatrick
1785061da546Spatrick auto load_addr_str = command[0].ref();
1786*f6aab3d8Srobert // Non-address bits in this will be handled later by GetMemoryRegion
1787061da546Spatrick load_addr = OptionArgParser::ToAddress(&m_exe_ctx, load_addr_str,
1788061da546Spatrick LLDB_INVALID_ADDRESS, &error);
1789061da546Spatrick if (error.Fail() || load_addr == LLDB_INVALID_ADDRESS) {
1790be691f3bSpatrick result.AppendErrorWithFormat("invalid address argument \"%s\": %s\n",
1791be691f3bSpatrick command[0].c_str(), error.AsCString());
1792be691f3bSpatrick return false;
1793061da546Spatrick }
1794*f6aab3d8Srobert } else if (argc > 1 ||
1795*f6aab3d8Srobert // When we're repeating the command, the previous end address is
1796*f6aab3d8Srobert // used for load_addr. If that was 0xF...F then we must have
1797*f6aab3d8Srobert // reached the end of memory.
1798*f6aab3d8Srobert (argc == 0 && !m_memory_region_options.m_all &&
1799*f6aab3d8Srobert load_addr == LLDB_INVALID_ADDRESS) ||
1800*f6aab3d8Srobert // If the target has non-address bits (tags, limited virtual
1801*f6aab3d8Srobert // address size, etc.), the end of mappable memory will be lower
1802*f6aab3d8Srobert // than that. So if we find any non-address bit set, we must be
1803*f6aab3d8Srobert // at the end of the mappable range.
1804*f6aab3d8Srobert (abi && (abi->FixAnyAddress(load_addr) != load_addr))) {
1805*f6aab3d8Srobert result.AppendErrorWithFormat(
1806*f6aab3d8Srobert "'%s' takes one argument or \"--all\" option:\nUsage: %s\n",
1807*f6aab3d8Srobert m_cmd_name.c_str(), m_cmd_syntax.c_str());
1808*f6aab3d8Srobert return false;
1809061da546Spatrick }
1810061da546Spatrick
1811*f6aab3d8Srobert // Is is important that we track the address used to request the region as
1812*f6aab3d8Srobert // this will give the correct section name in the case that regions overlap.
1813*f6aab3d8Srobert // On Windows we get mutliple regions that start at the same place but are
1814*f6aab3d8Srobert // different sizes and refer to different sections.
1815*f6aab3d8Srobert std::vector<std::pair<lldb_private::MemoryRegionInfo, lldb::addr_t>>
1816*f6aab3d8Srobert region_list;
1817*f6aab3d8Srobert if (m_memory_region_options.m_all) {
1818*f6aab3d8Srobert // We don't use GetMemoryRegions here because it doesn't include unmapped
1819*f6aab3d8Srobert // areas like repeating the command would. So instead, emulate doing that.
1820*f6aab3d8Srobert lldb::addr_t addr = 0;
1821*f6aab3d8Srobert while (error.Success() && addr != LLDB_INVALID_ADDRESS &&
1822*f6aab3d8Srobert // When there are non-address bits the last range will not extend
1823*f6aab3d8Srobert // to LLDB_INVALID_ADDRESS but to the max virtual address.
1824*f6aab3d8Srobert // This prevents us looping forever if that is the case.
1825*f6aab3d8Srobert (!abi || (abi->FixAnyAddress(addr) == addr))) {
1826*f6aab3d8Srobert lldb_private::MemoryRegionInfo region_info;
1827*f6aab3d8Srobert error = process_sp->GetMemoryRegionInfo(addr, region_info);
1828*f6aab3d8Srobert
1829061da546Spatrick if (error.Success()) {
1830*f6aab3d8Srobert region_list.push_back({region_info, addr});
1831*f6aab3d8Srobert addr = region_info.GetRange().GetRangeEnd();
1832061da546Spatrick }
1833061da546Spatrick }
1834*f6aab3d8Srobert } else {
1835*f6aab3d8Srobert lldb_private::MemoryRegionInfo region_info;
1836*f6aab3d8Srobert error = process_sp->GetMemoryRegionInfo(load_addr, region_info);
1837*f6aab3d8Srobert if (error.Success())
1838*f6aab3d8Srobert region_list.push_back({region_info, load_addr});
1839*f6aab3d8Srobert }
1840be691f3bSpatrick
1841*f6aab3d8Srobert if (error.Success()) {
1842*f6aab3d8Srobert for (std::pair<MemoryRegionInfo, addr_t> &range : region_list) {
1843*f6aab3d8Srobert DumpRegion(result, process_sp->GetTarget(), range.first, range.second);
1844*f6aab3d8Srobert m_prev_end_addr = range.first.GetRange().GetRangeEnd();
1845be691f3bSpatrick }
1846be691f3bSpatrick
1847061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
1848be691f3bSpatrick return true;
1849be691f3bSpatrick }
1850be691f3bSpatrick
1851061da546Spatrick result.AppendErrorWithFormat("%s\n", error.AsCString());
1852be691f3bSpatrick return false;
1853061da546Spatrick }
1854061da546Spatrick
GetRepeatCommand(Args & current_command_args,uint32_t index)1855*f6aab3d8Srobert std::optional<std::string> GetRepeatCommand(Args ¤t_command_args,
1856061da546Spatrick uint32_t index) override {
1857061da546Spatrick // If we repeat this command, repeat it without any arguments so we can
1858061da546Spatrick // show the next memory range
1859*f6aab3d8Srobert return m_cmd_name;
1860061da546Spatrick }
1861061da546Spatrick
1862*f6aab3d8Srobert lldb::addr_t m_prev_end_addr = LLDB_INVALID_ADDRESS;
1863*f6aab3d8Srobert
1864*f6aab3d8Srobert OptionGroupOptions m_option_group;
1865*f6aab3d8Srobert OptionGroupMemoryRegion m_memory_region_options;
1866061da546Spatrick };
1867061da546Spatrick
1868061da546Spatrick // CommandObjectMemory
1869061da546Spatrick
CommandObjectMemory(CommandInterpreter & interpreter)1870061da546Spatrick CommandObjectMemory::CommandObjectMemory(CommandInterpreter &interpreter)
1871061da546Spatrick : CommandObjectMultiword(
1872061da546Spatrick interpreter, "memory",
1873061da546Spatrick "Commands for operating on memory in the current target process.",
1874061da546Spatrick "memory <subcommand> [<subcommand-options>]") {
1875061da546Spatrick LoadSubCommand("find",
1876061da546Spatrick CommandObjectSP(new CommandObjectMemoryFind(interpreter)));
1877061da546Spatrick LoadSubCommand("read",
1878061da546Spatrick CommandObjectSP(new CommandObjectMemoryRead(interpreter)));
1879061da546Spatrick LoadSubCommand("write",
1880061da546Spatrick CommandObjectSP(new CommandObjectMemoryWrite(interpreter)));
1881061da546Spatrick LoadSubCommand("history",
1882061da546Spatrick CommandObjectSP(new CommandObjectMemoryHistory(interpreter)));
1883061da546Spatrick LoadSubCommand("region",
1884061da546Spatrick CommandObjectSP(new CommandObjectMemoryRegion(interpreter)));
1885be691f3bSpatrick LoadSubCommand("tag",
1886be691f3bSpatrick CommandObjectSP(new CommandObjectMemoryTag(interpreter)));
1887061da546Spatrick }
1888061da546Spatrick
1889061da546Spatrick CommandObjectMemory::~CommandObjectMemory() = default;
1890