1 //===-- CommandObjectMemory.cpp ---------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "CommandObjectMemory.h"
10 #include "lldb/Core/Debugger.h"
11 #include "lldb/Core/DumpDataExtractor.h"
12 #include "lldb/Core/Module.h"
13 #include "lldb/Core/Section.h"
14 #include "lldb/Core/ValueObjectMemory.h"
15 #include "lldb/DataFormatters/ValueObjectPrinter.h"
16 #include "lldb/Expression/ExpressionVariable.h"
17 #include "lldb/Host/OptionParser.h"
18 #include "lldb/Interpreter/CommandInterpreter.h"
19 #include "lldb/Interpreter/CommandReturnObject.h"
20 #include "lldb/Interpreter/OptionArgParser.h"
21 #include "lldb/Interpreter/OptionGroupFormat.h"
22 #include "lldb/Interpreter/OptionGroupOutputFile.h"
23 #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
24 #include "lldb/Interpreter/OptionValueLanguage.h"
25 #include "lldb/Interpreter/OptionValueString.h"
26 #include "lldb/Interpreter/Options.h"
27 #include "lldb/Symbol/SymbolFile.h"
28 #include "lldb/Symbol/TypeList.h"
29 #include "lldb/Target/Language.h"
30 #include "lldb/Target/MemoryHistory.h"
31 #include "lldb/Target/MemoryRegionInfo.h"
32 #include "lldb/Target/Process.h"
33 #include "lldb/Target/StackFrame.h"
34 #include "lldb/Target/Target.h"
35 #include "lldb/Target/Thread.h"
36 #include "lldb/Utility/Args.h"
37 #include "lldb/Utility/DataBufferHeap.h"
38 #include "lldb/Utility/DataBufferLLVM.h"
39 #include "lldb/Utility/StreamString.h"
40 
41 #include "lldb/lldb-private.h"
42 
43 #include <cinttypes>
44 #include <memory>
45 
46 using namespace lldb;
47 using namespace lldb_private;
48 
49 #define LLDB_OPTIONS_memory_read
50 #include "CommandOptions.inc"
51 
52 class OptionGroupReadMemory : public OptionGroup {
53 public:
54   OptionGroupReadMemory()
55       : m_num_per_line(1, 1), m_output_as_binary(false), m_view_as_type(),
56         m_offset(0, 0), m_language_for_type(eLanguageTypeUnknown) {}
57 
58   ~OptionGroupReadMemory() override = default;
59 
60   llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
61     return llvm::makeArrayRef(g_memory_read_options);
62   }
63 
64   Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
65                         ExecutionContext *execution_context) override {
66     Status error;
67     const int short_option = g_memory_read_options[option_idx].short_option;
68 
69     switch (short_option) {
70     case 'l':
71       error = m_num_per_line.SetValueFromString(option_value);
72       if (m_num_per_line.GetCurrentValue() == 0)
73         error.SetErrorStringWithFormat(
74             "invalid value for --num-per-line option '%s'",
75             option_value.str().c_str());
76       break;
77 
78     case 'b':
79       m_output_as_binary = true;
80       break;
81 
82     case 't':
83       error = m_view_as_type.SetValueFromString(option_value);
84       break;
85 
86     case 'r':
87       m_force = true;
88       break;
89 
90     case 'x':
91       error = m_language_for_type.SetValueFromString(option_value);
92       break;
93 
94     case 'E':
95       error = m_offset.SetValueFromString(option_value);
96       break;
97 
98     default:
99       error.SetErrorStringWithFormat("unrecognized short option '%c'",
100                                      short_option);
101       break;
102     }
103     return error;
104   }
105 
106   void OptionParsingStarting(ExecutionContext *execution_context) override {
107     m_num_per_line.Clear();
108     m_output_as_binary = false;
109     m_view_as_type.Clear();
110     m_force = false;
111     m_offset.Clear();
112     m_language_for_type.Clear();
113   }
114 
115   Status FinalizeSettings(Target *target, OptionGroupFormat &format_options) {
116     Status error;
117     OptionValueUInt64 &byte_size_value = format_options.GetByteSizeValue();
118     OptionValueUInt64 &count_value = format_options.GetCountValue();
119     const bool byte_size_option_set = byte_size_value.OptionWasSet();
120     const bool num_per_line_option_set = m_num_per_line.OptionWasSet();
121     const bool count_option_set = format_options.GetCountValue().OptionWasSet();
122 
123     switch (format_options.GetFormat()) {
124     default:
125       break;
126 
127     case eFormatBoolean:
128       if (!byte_size_option_set)
129         byte_size_value = 1;
130       if (!num_per_line_option_set)
131         m_num_per_line = 1;
132       if (!count_option_set)
133         format_options.GetCountValue() = 8;
134       break;
135 
136     case eFormatCString:
137       break;
138 
139     case eFormatInstruction:
140       if (count_option_set)
141         byte_size_value = target->GetArchitecture().GetMaximumOpcodeByteSize();
142       m_num_per_line = 1;
143       break;
144 
145     case eFormatAddressInfo:
146       if (!byte_size_option_set)
147         byte_size_value = target->GetArchitecture().GetAddressByteSize();
148       m_num_per_line = 1;
149       if (!count_option_set)
150         format_options.GetCountValue() = 8;
151       break;
152 
153     case eFormatPointer:
154       byte_size_value = target->GetArchitecture().GetAddressByteSize();
155       if (!num_per_line_option_set)
156         m_num_per_line = 4;
157       if (!count_option_set)
158         format_options.GetCountValue() = 8;
159       break;
160 
161     case eFormatBinary:
162     case eFormatFloat:
163     case eFormatOctal:
164     case eFormatDecimal:
165     case eFormatEnum:
166     case eFormatUnicode16:
167     case eFormatUnicode32:
168     case eFormatUnsigned:
169     case eFormatHexFloat:
170       if (!byte_size_option_set)
171         byte_size_value = 4;
172       if (!num_per_line_option_set)
173         m_num_per_line = 1;
174       if (!count_option_set)
175         format_options.GetCountValue() = 8;
176       break;
177 
178     case eFormatBytes:
179     case eFormatBytesWithASCII:
180       if (byte_size_option_set) {
181         if (byte_size_value > 1)
182           error.SetErrorStringWithFormat(
183               "display format (bytes/bytes with ASCII) conflicts with the "
184               "specified byte size %" PRIu64 "\n"
185               "\tconsider using a different display format or don't specify "
186               "the byte size.",
187               byte_size_value.GetCurrentValue());
188       } else
189         byte_size_value = 1;
190       if (!num_per_line_option_set)
191         m_num_per_line = 16;
192       if (!count_option_set)
193         format_options.GetCountValue() = 32;
194       break;
195 
196     case eFormatCharArray:
197     case eFormatChar:
198     case eFormatCharPrintable:
199       if (!byte_size_option_set)
200         byte_size_value = 1;
201       if (!num_per_line_option_set)
202         m_num_per_line = 32;
203       if (!count_option_set)
204         format_options.GetCountValue() = 64;
205       break;
206 
207     case eFormatComplex:
208       if (!byte_size_option_set)
209         byte_size_value = 8;
210       if (!num_per_line_option_set)
211         m_num_per_line = 1;
212       if (!count_option_set)
213         format_options.GetCountValue() = 8;
214       break;
215 
216     case eFormatComplexInteger:
217       if (!byte_size_option_set)
218         byte_size_value = 8;
219       if (!num_per_line_option_set)
220         m_num_per_line = 1;
221       if (!count_option_set)
222         format_options.GetCountValue() = 8;
223       break;
224 
225     case eFormatHex:
226       if (!byte_size_option_set)
227         byte_size_value = 4;
228       if (!num_per_line_option_set) {
229         switch (byte_size_value) {
230         case 1:
231         case 2:
232           m_num_per_line = 8;
233           break;
234         case 4:
235           m_num_per_line = 4;
236           break;
237         case 8:
238           m_num_per_line = 2;
239           break;
240         default:
241           m_num_per_line = 1;
242           break;
243         }
244       }
245       if (!count_option_set)
246         count_value = 8;
247       break;
248 
249     case eFormatVectorOfChar:
250     case eFormatVectorOfSInt8:
251     case eFormatVectorOfUInt8:
252     case eFormatVectorOfSInt16:
253     case eFormatVectorOfUInt16:
254     case eFormatVectorOfSInt32:
255     case eFormatVectorOfUInt32:
256     case eFormatVectorOfSInt64:
257     case eFormatVectorOfUInt64:
258     case eFormatVectorOfFloat16:
259     case eFormatVectorOfFloat32:
260     case eFormatVectorOfFloat64:
261     case eFormatVectorOfUInt128:
262       if (!byte_size_option_set)
263         byte_size_value = 128;
264       if (!num_per_line_option_set)
265         m_num_per_line = 1;
266       if (!count_option_set)
267         count_value = 4;
268       break;
269     }
270     return error;
271   }
272 
273   bool AnyOptionWasSet() const {
274     return m_num_per_line.OptionWasSet() || m_output_as_binary ||
275            m_view_as_type.OptionWasSet() || m_offset.OptionWasSet() ||
276            m_language_for_type.OptionWasSet();
277   }
278 
279   OptionValueUInt64 m_num_per_line;
280   bool m_output_as_binary;
281   OptionValueString m_view_as_type;
282   bool m_force;
283   OptionValueUInt64 m_offset;
284   OptionValueLanguage m_language_for_type;
285 };
286 
287 // Read memory from the inferior process
288 class CommandObjectMemoryRead : public CommandObjectParsed {
289 public:
290   CommandObjectMemoryRead(CommandInterpreter &interpreter)
291       : CommandObjectParsed(
292             interpreter, "memory read",
293             "Read from the memory of the current target process.", nullptr,
294             eCommandRequiresTarget | eCommandProcessMustBePaused),
295         m_option_group(), m_format_options(eFormatBytesWithASCII, 1, 8),
296         m_memory_options(), m_outfile_options(), m_varobj_options(),
297         m_next_addr(LLDB_INVALID_ADDRESS), m_prev_byte_size(0),
298         m_prev_format_options(eFormatBytesWithASCII, 1, 8),
299         m_prev_memory_options(), m_prev_outfile_options(),
300         m_prev_varobj_options() {
301     CommandArgumentEntry arg1;
302     CommandArgumentEntry arg2;
303     CommandArgumentData start_addr_arg;
304     CommandArgumentData end_addr_arg;
305 
306     // Define the first (and only) variant of this arg.
307     start_addr_arg.arg_type = eArgTypeAddressOrExpression;
308     start_addr_arg.arg_repetition = eArgRepeatPlain;
309 
310     // There is only one variant this argument could be; put it into the
311     // argument entry.
312     arg1.push_back(start_addr_arg);
313 
314     // Define the first (and only) variant of this arg.
315     end_addr_arg.arg_type = eArgTypeAddressOrExpression;
316     end_addr_arg.arg_repetition = eArgRepeatOptional;
317 
318     // There is only one variant this argument could be; put it into the
319     // argument entry.
320     arg2.push_back(end_addr_arg);
321 
322     // Push the data for the first argument into the m_arguments vector.
323     m_arguments.push_back(arg1);
324     m_arguments.push_back(arg2);
325 
326     // Add the "--format" and "--count" options to group 1 and 3
327     m_option_group.Append(&m_format_options,
328                           OptionGroupFormat::OPTION_GROUP_FORMAT |
329                               OptionGroupFormat::OPTION_GROUP_COUNT,
330                           LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3);
331     m_option_group.Append(&m_format_options,
332                           OptionGroupFormat::OPTION_GROUP_GDB_FMT,
333                           LLDB_OPT_SET_1 | LLDB_OPT_SET_3);
334     // Add the "--size" option to group 1 and 2
335     m_option_group.Append(&m_format_options,
336                           OptionGroupFormat::OPTION_GROUP_SIZE,
337                           LLDB_OPT_SET_1 | LLDB_OPT_SET_2);
338     m_option_group.Append(&m_memory_options);
339     m_option_group.Append(&m_outfile_options, LLDB_OPT_SET_ALL,
340                           LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3);
341     m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_3);
342     m_option_group.Finalize();
343   }
344 
345   ~CommandObjectMemoryRead() override = default;
346 
347   Options *GetOptions() override { return &m_option_group; }
348 
349   const char *GetRepeatCommand(Args &current_command_args,
350                                uint32_t index) override {
351     return m_cmd_name.c_str();
352   }
353 
354 protected:
355   bool DoExecute(Args &command, CommandReturnObject &result) override {
356     // No need to check "target" for validity as eCommandRequiresTarget ensures
357     // it is valid
358     Target *target = m_exe_ctx.GetTargetPtr();
359 
360     const size_t argc = command.GetArgumentCount();
361 
362     if ((argc == 0 && m_next_addr == LLDB_INVALID_ADDRESS) || argc > 2) {
363       result.AppendErrorWithFormat("%s takes a start address expression with "
364                                    "an optional end address expression.\n",
365                                    m_cmd_name.c_str());
366       result.AppendRawWarning("Expressions should be quoted if they contain "
367                               "spaces or other special characters.\n");
368       result.SetStatus(eReturnStatusFailed);
369       return false;
370     }
371 
372     CompilerType compiler_type;
373     Status error;
374 
375     const char *view_as_type_cstr =
376         m_memory_options.m_view_as_type.GetCurrentValue();
377     if (view_as_type_cstr && view_as_type_cstr[0]) {
378       // We are viewing memory as a type
379 
380       const bool exact_match = false;
381       TypeList type_list;
382       uint32_t reference_count = 0;
383       uint32_t pointer_count = 0;
384       size_t idx;
385 
386 #define ALL_KEYWORDS                                                           \
387   KEYWORD("const")                                                             \
388   KEYWORD("volatile")                                                          \
389   KEYWORD("restrict")                                                          \
390   KEYWORD("struct")                                                            \
391   KEYWORD("class")                                                             \
392   KEYWORD("union")
393 
394 #define KEYWORD(s) s,
395       static const char *g_keywords[] = {ALL_KEYWORDS};
396 #undef KEYWORD
397 
398 #define KEYWORD(s) (sizeof(s) - 1),
399       static const int g_keyword_lengths[] = {ALL_KEYWORDS};
400 #undef KEYWORD
401 
402 #undef ALL_KEYWORDS
403 
404       static size_t g_num_keywords = sizeof(g_keywords) / sizeof(const char *);
405       std::string type_str(view_as_type_cstr);
406 
407       // Remove all instances of g_keywords that are followed by spaces
408       for (size_t i = 0; i < g_num_keywords; ++i) {
409         const char *keyword = g_keywords[i];
410         int keyword_len = g_keyword_lengths[i];
411 
412         idx = 0;
413         while ((idx = type_str.find(keyword, idx)) != std::string::npos) {
414           if (type_str[idx + keyword_len] == ' ' ||
415               type_str[idx + keyword_len] == '\t') {
416             type_str.erase(idx, keyword_len + 1);
417             idx = 0;
418           } else {
419             idx += keyword_len;
420           }
421         }
422       }
423       bool done = type_str.empty();
424       //
425       idx = type_str.find_first_not_of(" \t");
426       if (idx > 0 && idx != std::string::npos)
427         type_str.erase(0, idx);
428       while (!done) {
429         // Strip trailing spaces
430         if (type_str.empty())
431           done = true;
432         else {
433           switch (type_str[type_str.size() - 1]) {
434           case '*':
435             ++pointer_count;
436             LLVM_FALLTHROUGH;
437           case ' ':
438           case '\t':
439             type_str.erase(type_str.size() - 1);
440             break;
441 
442           case '&':
443             if (reference_count == 0) {
444               reference_count = 1;
445               type_str.erase(type_str.size() - 1);
446             } else {
447               result.AppendErrorWithFormat("invalid type string: '%s'\n",
448                                            view_as_type_cstr);
449               result.SetStatus(eReturnStatusFailed);
450               return false;
451             }
452             break;
453 
454           default:
455             done = true;
456             break;
457           }
458         }
459       }
460 
461       llvm::DenseSet<lldb_private::SymbolFile *> searched_symbol_files;
462       ConstString lookup_type_name(type_str.c_str());
463       StackFrame *frame = m_exe_ctx.GetFramePtr();
464       ModuleSP search_first;
465       if (frame) {
466         search_first = frame->GetSymbolContext(eSymbolContextModule).module_sp;
467       }
468       target->GetImages().FindTypes(search_first.get(), lookup_type_name,
469                                     exact_match, 1, searched_symbol_files,
470                                     type_list);
471 
472       if (type_list.GetSize() == 0 && lookup_type_name.GetCString()) {
473         LanguageType language_for_type =
474             m_memory_options.m_language_for_type.GetCurrentValue();
475         std::set<LanguageType> languages_to_check;
476         if (language_for_type != eLanguageTypeUnknown) {
477           languages_to_check.insert(language_for_type);
478         } else {
479           languages_to_check = Language::GetSupportedLanguages();
480         }
481 
482         std::set<CompilerType> user_defined_types;
483         for (auto lang : languages_to_check) {
484           if (auto *persistent_vars =
485                   target->GetPersistentExpressionStateForLanguage(lang)) {
486             if (llvm::Optional<CompilerType> type =
487                     persistent_vars->GetCompilerTypeFromPersistentDecl(
488                         lookup_type_name)) {
489               user_defined_types.emplace(*type);
490             }
491           }
492         }
493 
494         if (user_defined_types.size() > 1) {
495           result.AppendErrorWithFormat(
496               "Mutiple types found matching raw type '%s', please disambiguate "
497               "by specifying the language with -x",
498               lookup_type_name.GetCString());
499           result.SetStatus(eReturnStatusFailed);
500           return false;
501         }
502 
503         if (user_defined_types.size() == 1) {
504           compiler_type = *user_defined_types.begin();
505         }
506       }
507 
508       if (!compiler_type.IsValid()) {
509         if (type_list.GetSize() == 0) {
510           result.AppendErrorWithFormat("unable to find any types that match "
511                                        "the raw type '%s' for full type '%s'\n",
512                                        lookup_type_name.GetCString(),
513                                        view_as_type_cstr);
514           result.SetStatus(eReturnStatusFailed);
515           return false;
516         } else {
517           TypeSP type_sp(type_list.GetTypeAtIndex(0));
518           compiler_type = type_sp->GetFullCompilerType();
519         }
520       }
521 
522       while (pointer_count > 0) {
523         CompilerType pointer_type = compiler_type.GetPointerType();
524         if (pointer_type.IsValid())
525           compiler_type = pointer_type;
526         else {
527           result.AppendError("unable make a pointer type\n");
528           result.SetStatus(eReturnStatusFailed);
529           return false;
530         }
531         --pointer_count;
532       }
533 
534       llvm::Optional<uint64_t> size = compiler_type.GetByteSize(nullptr);
535       if (!size) {
536         result.AppendErrorWithFormat(
537             "unable to get the byte size of the type '%s'\n",
538             view_as_type_cstr);
539         result.SetStatus(eReturnStatusFailed);
540         return false;
541       }
542       m_format_options.GetByteSizeValue() = *size;
543 
544       if (!m_format_options.GetCountValue().OptionWasSet())
545         m_format_options.GetCountValue() = 1;
546     } else {
547       error = m_memory_options.FinalizeSettings(target, m_format_options);
548     }
549 
550     // Look for invalid combinations of settings
551     if (error.Fail()) {
552       result.AppendError(error.AsCString());
553       result.SetStatus(eReturnStatusFailed);
554       return false;
555     }
556 
557     lldb::addr_t addr;
558     size_t total_byte_size = 0;
559     if (argc == 0) {
560       // Use the last address and byte size and all options as they were if no
561       // options have been set
562       addr = m_next_addr;
563       total_byte_size = m_prev_byte_size;
564       compiler_type = m_prev_compiler_type;
565       if (!m_format_options.AnyOptionWasSet() &&
566           !m_memory_options.AnyOptionWasSet() &&
567           !m_outfile_options.AnyOptionWasSet() &&
568           !m_varobj_options.AnyOptionWasSet()) {
569         m_format_options = m_prev_format_options;
570         m_memory_options = m_prev_memory_options;
571         m_outfile_options = m_prev_outfile_options;
572         m_varobj_options = m_prev_varobj_options;
573       }
574     }
575 
576     size_t item_count = m_format_options.GetCountValue().GetCurrentValue();
577 
578     // TODO For non-8-bit byte addressable architectures this needs to be
579     // revisited to fully support all lldb's range of formatting options.
580     // Furthermore code memory reads (for those architectures) will not be
581     // correctly formatted even w/o formatting options.
582     size_t item_byte_size =
583         target->GetArchitecture().GetDataByteSize() > 1
584             ? target->GetArchitecture().GetDataByteSize()
585             : m_format_options.GetByteSizeValue().GetCurrentValue();
586 
587     const size_t num_per_line =
588         m_memory_options.m_num_per_line.GetCurrentValue();
589 
590     if (total_byte_size == 0) {
591       total_byte_size = item_count * item_byte_size;
592       if (total_byte_size == 0)
593         total_byte_size = 32;
594     }
595 
596     if (argc > 0)
597       addr = OptionArgParser::ToAddress(&m_exe_ctx, command[0].ref,
598                                         LLDB_INVALID_ADDRESS, &error);
599 
600     if (addr == LLDB_INVALID_ADDRESS) {
601       result.AppendError("invalid start address expression.");
602       result.AppendError(error.AsCString());
603       result.SetStatus(eReturnStatusFailed);
604       return false;
605     }
606 
607     if (argc == 2) {
608       lldb::addr_t end_addr = OptionArgParser::ToAddress(
609           &m_exe_ctx, command[1].ref, LLDB_INVALID_ADDRESS, nullptr);
610       if (end_addr == LLDB_INVALID_ADDRESS) {
611         result.AppendError("invalid end address expression.");
612         result.AppendError(error.AsCString());
613         result.SetStatus(eReturnStatusFailed);
614         return false;
615       } else if (end_addr <= addr) {
616         result.AppendErrorWithFormat(
617             "end address (0x%" PRIx64
618             ") must be greater that the start address (0x%" PRIx64 ").\n",
619             end_addr, addr);
620         result.SetStatus(eReturnStatusFailed);
621         return false;
622       } else if (m_format_options.GetCountValue().OptionWasSet()) {
623         result.AppendErrorWithFormat(
624             "specify either the end address (0x%" PRIx64
625             ") or the count (--count %" PRIu64 "), not both.\n",
626             end_addr, (uint64_t)item_count);
627         result.SetStatus(eReturnStatusFailed);
628         return false;
629       }
630 
631       total_byte_size = end_addr - addr;
632       item_count = total_byte_size / item_byte_size;
633     }
634 
635     uint32_t max_unforced_size = target->GetMaximumMemReadSize();
636 
637     if (total_byte_size > max_unforced_size && !m_memory_options.m_force) {
638       result.AppendErrorWithFormat(
639           "Normally, \'memory read\' will not read over %" PRIu32
640           " bytes of data.\n",
641           max_unforced_size);
642       result.AppendErrorWithFormat(
643           "Please use --force to override this restriction just once.\n");
644       result.AppendErrorWithFormat("or set target.max-memory-read-size if you "
645                                    "will often need a larger limit.\n");
646       return false;
647     }
648 
649     DataBufferSP data_sp;
650     size_t bytes_read = 0;
651     if (compiler_type.GetOpaqueQualType()) {
652       // Make sure we don't display our type as ASCII bytes like the default
653       // memory read
654       if (!m_format_options.GetFormatValue().OptionWasSet())
655         m_format_options.GetFormatValue().SetCurrentValue(eFormatDefault);
656 
657       llvm::Optional<uint64_t> size = compiler_type.GetByteSize(nullptr);
658       if (!size) {
659         result.AppendError("can't get size of type");
660         return false;
661       }
662       bytes_read = *size * m_format_options.GetCountValue().GetCurrentValue();
663 
664       if (argc > 0)
665         addr = addr + (*size * m_memory_options.m_offset.GetCurrentValue());
666     } else if (m_format_options.GetFormatValue().GetCurrentValue() !=
667                eFormatCString) {
668       data_sp = std::make_shared<DataBufferHeap>(total_byte_size, '\0');
669       if (data_sp->GetBytes() == nullptr) {
670         result.AppendErrorWithFormat(
671             "can't allocate 0x%" PRIx32
672             " bytes for the memory read buffer, specify a smaller size to read",
673             (uint32_t)total_byte_size);
674         result.SetStatus(eReturnStatusFailed);
675         return false;
676       }
677 
678       Address address(addr, nullptr);
679       bytes_read = target->ReadMemory(address, false, data_sp->GetBytes(),
680                                       data_sp->GetByteSize(), error);
681       if (bytes_read == 0) {
682         const char *error_cstr = error.AsCString();
683         if (error_cstr && error_cstr[0]) {
684           result.AppendError(error_cstr);
685         } else {
686           result.AppendErrorWithFormat(
687               "failed to read memory from 0x%" PRIx64 ".\n", addr);
688         }
689         result.SetStatus(eReturnStatusFailed);
690         return false;
691       }
692 
693       if (bytes_read < total_byte_size)
694         result.AppendWarningWithFormat(
695             "Not all bytes (%" PRIu64 "/%" PRIu64
696             ") were able to be read from 0x%" PRIx64 ".\n",
697             (uint64_t)bytes_read, (uint64_t)total_byte_size, addr);
698     } else {
699       // we treat c-strings as a special case because they do not have a fixed
700       // size
701       if (m_format_options.GetByteSizeValue().OptionWasSet() &&
702           !m_format_options.HasGDBFormat())
703         item_byte_size = m_format_options.GetByteSizeValue().GetCurrentValue();
704       else
705         item_byte_size = target->GetMaximumSizeOfStringSummary();
706       if (!m_format_options.GetCountValue().OptionWasSet())
707         item_count = 1;
708       data_sp = std::make_shared<DataBufferHeap>(
709           (item_byte_size + 1) * item_count,
710           '\0'); // account for NULLs as necessary
711       if (data_sp->GetBytes() == nullptr) {
712         result.AppendErrorWithFormat(
713             "can't allocate 0x%" PRIx64
714             " bytes for the memory read buffer, specify a smaller size to read",
715             (uint64_t)((item_byte_size + 1) * item_count));
716         result.SetStatus(eReturnStatusFailed);
717         return false;
718       }
719       uint8_t *data_ptr = data_sp->GetBytes();
720       auto data_addr = addr;
721       auto count = item_count;
722       item_count = 0;
723       bool break_on_no_NULL = false;
724       while (item_count < count) {
725         std::string buffer;
726         buffer.resize(item_byte_size + 1, 0);
727         Status error;
728         size_t read = target->ReadCStringFromMemory(data_addr, &buffer[0],
729                                                     item_byte_size + 1, error);
730         if (error.Fail()) {
731           result.AppendErrorWithFormat(
732               "failed to read memory from 0x%" PRIx64 ".\n", addr);
733           result.SetStatus(eReturnStatusFailed);
734           return false;
735         }
736 
737         if (item_byte_size == read) {
738           result.AppendWarningWithFormat(
739               "unable to find a NULL terminated string at 0x%" PRIx64
740               ".Consider increasing the maximum read length.\n",
741               data_addr);
742           --read;
743           break_on_no_NULL = true;
744         } else
745           ++read; // account for final NULL byte
746 
747         memcpy(data_ptr, &buffer[0], read);
748         data_ptr += read;
749         data_addr += read;
750         bytes_read += read;
751         item_count++; // if we break early we know we only read item_count
752                       // strings
753 
754         if (break_on_no_NULL)
755           break;
756       }
757       data_sp =
758           std::make_shared<DataBufferHeap>(data_sp->GetBytes(), bytes_read + 1);
759     }
760 
761     m_next_addr = addr + bytes_read;
762     m_prev_byte_size = bytes_read;
763     m_prev_format_options = m_format_options;
764     m_prev_memory_options = m_memory_options;
765     m_prev_outfile_options = m_outfile_options;
766     m_prev_varobj_options = m_varobj_options;
767     m_prev_compiler_type = compiler_type;
768 
769     StreamFile outfile_stream;
770     Stream *output_stream = nullptr;
771     const FileSpec &outfile_spec =
772         m_outfile_options.GetFile().GetCurrentValue();
773 
774     std::string path = outfile_spec.GetPath();
775     if (outfile_spec) {
776 
777       uint32_t open_options =
778           File::eOpenOptionWrite | File::eOpenOptionCanCreate;
779       const bool append = m_outfile_options.GetAppend().GetCurrentValue();
780       if (append)
781         open_options |= File::eOpenOptionAppend;
782 
783       Status error = FileSystem::Instance().Open(outfile_stream.GetFile(),
784                                                  outfile_spec, open_options);
785       if (error.Success()) {
786         if (m_memory_options.m_output_as_binary) {
787           const size_t bytes_written =
788               outfile_stream.Write(data_sp->GetBytes(), bytes_read);
789           if (bytes_written > 0) {
790             result.GetOutputStream().Printf(
791                 "%zi bytes %s to '%s'\n", bytes_written,
792                 append ? "appended" : "written", path.c_str());
793             return true;
794           } else {
795             result.AppendErrorWithFormat("Failed to write %" PRIu64
796                                          " bytes to '%s'.\n",
797                                          (uint64_t)bytes_read, path.c_str());
798             result.SetStatus(eReturnStatusFailed);
799             return false;
800           }
801         } else {
802           // We are going to write ASCII to the file just point the
803           // output_stream to our outfile_stream...
804           output_stream = &outfile_stream;
805         }
806       } else {
807         result.AppendErrorWithFormat("Failed to open file '%s' for %s.\n",
808                                      path.c_str(), append ? "append" : "write");
809         result.SetStatus(eReturnStatusFailed);
810         return false;
811       }
812     } else {
813       output_stream = &result.GetOutputStream();
814     }
815 
816     ExecutionContextScope *exe_scope = m_exe_ctx.GetBestExecutionContextScope();
817     if (compiler_type.GetOpaqueQualType()) {
818       for (uint32_t i = 0; i < item_count; ++i) {
819         addr_t item_addr = addr + (i * item_byte_size);
820         Address address(item_addr);
821         StreamString name_strm;
822         name_strm.Printf("0x%" PRIx64, item_addr);
823         ValueObjectSP valobj_sp(ValueObjectMemory::Create(
824             exe_scope, name_strm.GetString(), address, compiler_type));
825         if (valobj_sp) {
826           Format format = m_format_options.GetFormat();
827           if (format != eFormatDefault)
828             valobj_sp->SetFormat(format);
829 
830           DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(
831               eLanguageRuntimeDescriptionDisplayVerbosityFull, format));
832 
833           valobj_sp->Dump(*output_stream, options);
834         } else {
835           result.AppendErrorWithFormat(
836               "failed to create a value object for: (%s) %s\n",
837               view_as_type_cstr, name_strm.GetData());
838           result.SetStatus(eReturnStatusFailed);
839           return false;
840         }
841       }
842       return true;
843     }
844 
845     result.SetStatus(eReturnStatusSuccessFinishResult);
846     DataExtractor data(data_sp, target->GetArchitecture().GetByteOrder(),
847                        target->GetArchitecture().GetAddressByteSize(),
848                        target->GetArchitecture().GetDataByteSize());
849 
850     Format format = m_format_options.GetFormat();
851     if (((format == eFormatChar) || (format == eFormatCharPrintable)) &&
852         (item_byte_size != 1)) {
853       // if a count was not passed, or it is 1
854       if (!m_format_options.GetCountValue().OptionWasSet() || item_count == 1) {
855         // this turns requests such as
856         // memory read -fc -s10 -c1 *charPtrPtr
857         // which make no sense (what is a char of size 10?) into a request for
858         // fetching 10 chars of size 1 from the same memory location
859         format = eFormatCharArray;
860         item_count = item_byte_size;
861         item_byte_size = 1;
862       } else {
863         // here we passed a count, and it was not 1 so we have a byte_size and
864         // a count we could well multiply those, but instead let's just fail
865         result.AppendErrorWithFormat(
866             "reading memory as characters of size %" PRIu64 " is not supported",
867             (uint64_t)item_byte_size);
868         result.SetStatus(eReturnStatusFailed);
869         return false;
870       }
871     }
872 
873     assert(output_stream);
874     size_t bytes_dumped = DumpDataExtractor(
875         data, output_stream, 0, format, item_byte_size, item_count,
876         num_per_line / target->GetArchitecture().GetDataByteSize(), addr, 0, 0,
877         exe_scope);
878     m_next_addr = addr + bytes_dumped;
879     output_stream->EOL();
880     return true;
881   }
882 
883   OptionGroupOptions m_option_group;
884   OptionGroupFormat m_format_options;
885   OptionGroupReadMemory m_memory_options;
886   OptionGroupOutputFile m_outfile_options;
887   OptionGroupValueObjectDisplay m_varobj_options;
888   lldb::addr_t m_next_addr;
889   lldb::addr_t m_prev_byte_size;
890   OptionGroupFormat m_prev_format_options;
891   OptionGroupReadMemory m_prev_memory_options;
892   OptionGroupOutputFile m_prev_outfile_options;
893   OptionGroupValueObjectDisplay m_prev_varobj_options;
894   CompilerType m_prev_compiler_type;
895 };
896 
897 #define LLDB_OPTIONS_memory_find
898 #include "CommandOptions.inc"
899 
900 // Find the specified data in memory
901 class CommandObjectMemoryFind : public CommandObjectParsed {
902 public:
903   class OptionGroupFindMemory : public OptionGroup {
904   public:
905     OptionGroupFindMemory() : OptionGroup(), m_count(1), m_offset(0) {}
906 
907     ~OptionGroupFindMemory() override = default;
908 
909     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
910       return llvm::makeArrayRef(g_memory_find_options);
911     }
912 
913     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
914                           ExecutionContext *execution_context) override {
915       Status error;
916       const int short_option = g_memory_find_options[option_idx].short_option;
917 
918       switch (short_option) {
919       case 'e':
920         m_expr.SetValueFromString(option_value);
921         break;
922 
923       case 's':
924         m_string.SetValueFromString(option_value);
925         break;
926 
927       case 'c':
928         if (m_count.SetValueFromString(option_value).Fail())
929           error.SetErrorString("unrecognized value for count");
930         break;
931 
932       case 'o':
933         if (m_offset.SetValueFromString(option_value).Fail())
934           error.SetErrorString("unrecognized value for dump-offset");
935         break;
936 
937       default:
938         error.SetErrorStringWithFormat("unrecognized short option '%c'",
939                                        short_option);
940         break;
941       }
942       return error;
943     }
944 
945     void OptionParsingStarting(ExecutionContext *execution_context) override {
946       m_expr.Clear();
947       m_string.Clear();
948       m_count.Clear();
949     }
950 
951     OptionValueString m_expr;
952     OptionValueString m_string;
953     OptionValueUInt64 m_count;
954     OptionValueUInt64 m_offset;
955   };
956 
957   CommandObjectMemoryFind(CommandInterpreter &interpreter)
958       : CommandObjectParsed(
959             interpreter, "memory find",
960             "Find a value in the memory of the current target process.",
961             nullptr, eCommandRequiresProcess | eCommandProcessMustBeLaunched),
962         m_option_group(), m_memory_options() {
963     CommandArgumentEntry arg1;
964     CommandArgumentEntry arg2;
965     CommandArgumentData addr_arg;
966     CommandArgumentData value_arg;
967 
968     // Define the first (and only) variant of this arg.
969     addr_arg.arg_type = eArgTypeAddressOrExpression;
970     addr_arg.arg_repetition = eArgRepeatPlain;
971 
972     // There is only one variant this argument could be; put it into the
973     // argument entry.
974     arg1.push_back(addr_arg);
975 
976     // Define the first (and only) variant of this arg.
977     value_arg.arg_type = eArgTypeAddressOrExpression;
978     value_arg.arg_repetition = eArgRepeatPlain;
979 
980     // There is only one variant this argument could be; put it into the
981     // argument entry.
982     arg2.push_back(value_arg);
983 
984     // Push the data for the first argument into the m_arguments vector.
985     m_arguments.push_back(arg1);
986     m_arguments.push_back(arg2);
987 
988     m_option_group.Append(&m_memory_options);
989     m_option_group.Finalize();
990   }
991 
992   ~CommandObjectMemoryFind() override = default;
993 
994   Options *GetOptions() override { return &m_option_group; }
995 
996 protected:
997   class ProcessMemoryIterator {
998   public:
999     ProcessMemoryIterator(ProcessSP process_sp, lldb::addr_t base)
1000         : m_process_sp(process_sp), m_base_addr(base), m_is_valid(true) {
1001       lldbassert(process_sp.get() != nullptr);
1002     }
1003 
1004     bool IsValid() { return m_is_valid; }
1005 
1006     uint8_t operator[](lldb::addr_t offset) {
1007       if (!IsValid())
1008         return 0;
1009 
1010       uint8_t retval = 0;
1011       Status error;
1012       if (0 ==
1013           m_process_sp->ReadMemory(m_base_addr + offset, &retval, 1, error)) {
1014         m_is_valid = false;
1015         return 0;
1016       }
1017 
1018       return retval;
1019     }
1020 
1021   private:
1022     ProcessSP m_process_sp;
1023     lldb::addr_t m_base_addr;
1024     bool m_is_valid;
1025   };
1026   bool DoExecute(Args &command, CommandReturnObject &result) override {
1027     // No need to check "process" for validity as eCommandRequiresProcess
1028     // ensures it is valid
1029     Process *process = m_exe_ctx.GetProcessPtr();
1030 
1031     const size_t argc = command.GetArgumentCount();
1032 
1033     if (argc != 2) {
1034       result.AppendError("two addresses needed for memory find");
1035       return false;
1036     }
1037 
1038     Status error;
1039     lldb::addr_t low_addr = OptionArgParser::ToAddress(
1040         &m_exe_ctx, command[0].ref, LLDB_INVALID_ADDRESS, &error);
1041     if (low_addr == LLDB_INVALID_ADDRESS || error.Fail()) {
1042       result.AppendError("invalid low address");
1043       return false;
1044     }
1045     lldb::addr_t high_addr = OptionArgParser::ToAddress(
1046         &m_exe_ctx, command[1].ref, LLDB_INVALID_ADDRESS, &error);
1047     if (high_addr == LLDB_INVALID_ADDRESS || error.Fail()) {
1048       result.AppendError("invalid high address");
1049       return false;
1050     }
1051 
1052     if (high_addr <= low_addr) {
1053       result.AppendError(
1054           "starting address must be smaller than ending address");
1055       return false;
1056     }
1057 
1058     lldb::addr_t found_location = LLDB_INVALID_ADDRESS;
1059 
1060     DataBufferHeap buffer;
1061 
1062     if (m_memory_options.m_string.OptionWasSet())
1063       buffer.CopyData(m_memory_options.m_string.GetStringValue());
1064     else if (m_memory_options.m_expr.OptionWasSet()) {
1065       StackFrame *frame = m_exe_ctx.GetFramePtr();
1066       ValueObjectSP result_sp;
1067       if ((eExpressionCompleted ==
1068            process->GetTarget().EvaluateExpression(
1069                m_memory_options.m_expr.GetStringValue(), frame, result_sp)) &&
1070           result_sp) {
1071         uint64_t value = result_sp->GetValueAsUnsigned(0);
1072         llvm::Optional<uint64_t> size =
1073             result_sp->GetCompilerType().GetByteSize(nullptr);
1074         if (!size)
1075           return false;
1076         switch (*size) {
1077         case 1: {
1078           uint8_t byte = (uint8_t)value;
1079           buffer.CopyData(&byte, 1);
1080         } break;
1081         case 2: {
1082           uint16_t word = (uint16_t)value;
1083           buffer.CopyData(&word, 2);
1084         } break;
1085         case 4: {
1086           uint32_t lword = (uint32_t)value;
1087           buffer.CopyData(&lword, 4);
1088         } break;
1089         case 8: {
1090           buffer.CopyData(&value, 8);
1091         } break;
1092         case 3:
1093         case 5:
1094         case 6:
1095         case 7:
1096           result.AppendError("unknown type. pass a string instead");
1097           return false;
1098         default:
1099           result.AppendError(
1100               "result size larger than 8 bytes. pass a string instead");
1101           return false;
1102         }
1103       } else {
1104         result.AppendError(
1105             "expression evaluation failed. pass a string instead");
1106         return false;
1107       }
1108     } else {
1109       result.AppendError(
1110           "please pass either a block of text, or an expression to evaluate.");
1111       return false;
1112     }
1113 
1114     size_t count = m_memory_options.m_count.GetCurrentValue();
1115     found_location = low_addr;
1116     bool ever_found = false;
1117     while (count) {
1118       found_location = FastSearch(found_location, high_addr, buffer.GetBytes(),
1119                                   buffer.GetByteSize());
1120       if (found_location == LLDB_INVALID_ADDRESS) {
1121         if (!ever_found) {
1122           result.AppendMessage("data not found within the range.\n");
1123           result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
1124         } else
1125           result.AppendMessage("no more matches within the range.\n");
1126         break;
1127       }
1128       result.AppendMessageWithFormat("data found at location: 0x%" PRIx64 "\n",
1129                                      found_location);
1130 
1131       DataBufferHeap dumpbuffer(32, 0);
1132       process->ReadMemory(
1133           found_location + m_memory_options.m_offset.GetCurrentValue(),
1134           dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(), error);
1135       if (!error.Fail()) {
1136         DataExtractor data(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(),
1137                            process->GetByteOrder(),
1138                            process->GetAddressByteSize());
1139         DumpDataExtractor(
1140             data, &result.GetOutputStream(), 0, lldb::eFormatBytesWithASCII, 1,
1141             dumpbuffer.GetByteSize(), 16,
1142             found_location + m_memory_options.m_offset.GetCurrentValue(), 0, 0);
1143         result.GetOutputStream().EOL();
1144       }
1145 
1146       --count;
1147       found_location++;
1148       ever_found = true;
1149     }
1150 
1151     result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
1152     return true;
1153   }
1154 
1155   lldb::addr_t FastSearch(lldb::addr_t low, lldb::addr_t high, uint8_t *buffer,
1156                           size_t buffer_size) {
1157     const size_t region_size = high - low;
1158 
1159     if (region_size < buffer_size)
1160       return LLDB_INVALID_ADDRESS;
1161 
1162     std::vector<size_t> bad_char_heuristic(256, buffer_size);
1163     ProcessSP process_sp = m_exe_ctx.GetProcessSP();
1164     ProcessMemoryIterator iterator(process_sp, low);
1165 
1166     for (size_t idx = 0; idx < buffer_size - 1; idx++) {
1167       decltype(bad_char_heuristic)::size_type bcu_idx = buffer[idx];
1168       bad_char_heuristic[bcu_idx] = buffer_size - idx - 1;
1169     }
1170     for (size_t s = 0; s <= (region_size - buffer_size);) {
1171       int64_t j = buffer_size - 1;
1172       while (j >= 0 && buffer[j] == iterator[s + j])
1173         j--;
1174       if (j < 0)
1175         return low + s;
1176       else
1177         s += bad_char_heuristic[iterator[s + buffer_size - 1]];
1178     }
1179 
1180     return LLDB_INVALID_ADDRESS;
1181   }
1182 
1183   OptionGroupOptions m_option_group;
1184   OptionGroupFindMemory m_memory_options;
1185 };
1186 
1187 #define LLDB_OPTIONS_memory_write
1188 #include "CommandOptions.inc"
1189 
1190 // Write memory to the inferior process
1191 class CommandObjectMemoryWrite : public CommandObjectParsed {
1192 public:
1193   class OptionGroupWriteMemory : public OptionGroup {
1194   public:
1195     OptionGroupWriteMemory() : OptionGroup() {}
1196 
1197     ~OptionGroupWriteMemory() override = default;
1198 
1199     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1200       return llvm::makeArrayRef(g_memory_write_options);
1201     }
1202 
1203     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
1204                           ExecutionContext *execution_context) override {
1205       Status error;
1206       const int short_option = g_memory_write_options[option_idx].short_option;
1207 
1208       switch (short_option) {
1209       case 'i':
1210         m_infile.SetFile(option_value, FileSpec::Style::native);
1211         FileSystem::Instance().Resolve(m_infile);
1212         if (!FileSystem::Instance().Exists(m_infile)) {
1213           m_infile.Clear();
1214           error.SetErrorStringWithFormat("input file does not exist: '%s'",
1215                                          option_value.str().c_str());
1216         }
1217         break;
1218 
1219       case 'o': {
1220         if (option_value.getAsInteger(0, m_infile_offset)) {
1221           m_infile_offset = 0;
1222           error.SetErrorStringWithFormat("invalid offset string '%s'",
1223                                          option_value.str().c_str());
1224         }
1225       } break;
1226 
1227       default:
1228         error.SetErrorStringWithFormat("unrecognized short option '%c'",
1229                                        short_option);
1230         break;
1231       }
1232       return error;
1233     }
1234 
1235     void OptionParsingStarting(ExecutionContext *execution_context) override {
1236       m_infile.Clear();
1237       m_infile_offset = 0;
1238     }
1239 
1240     FileSpec m_infile;
1241     off_t m_infile_offset;
1242   };
1243 
1244   CommandObjectMemoryWrite(CommandInterpreter &interpreter)
1245       : CommandObjectParsed(
1246             interpreter, "memory write",
1247             "Write to the memory of the current target process.", nullptr,
1248             eCommandRequiresProcess | eCommandProcessMustBeLaunched),
1249         m_option_group(), m_format_options(eFormatBytes, 1, UINT64_MAX),
1250         m_memory_options() {
1251     CommandArgumentEntry arg1;
1252     CommandArgumentEntry arg2;
1253     CommandArgumentData addr_arg;
1254     CommandArgumentData value_arg;
1255 
1256     // Define the first (and only) variant of this arg.
1257     addr_arg.arg_type = eArgTypeAddress;
1258     addr_arg.arg_repetition = eArgRepeatPlain;
1259 
1260     // There is only one variant this argument could be; put it into the
1261     // argument entry.
1262     arg1.push_back(addr_arg);
1263 
1264     // Define the first (and only) variant of this arg.
1265     value_arg.arg_type = eArgTypeValue;
1266     value_arg.arg_repetition = eArgRepeatPlus;
1267 
1268     // There is only one variant this argument could be; put it into the
1269     // argument entry.
1270     arg2.push_back(value_arg);
1271 
1272     // Push the data for the first argument into the m_arguments vector.
1273     m_arguments.push_back(arg1);
1274     m_arguments.push_back(arg2);
1275 
1276     m_option_group.Append(&m_format_options,
1277                           OptionGroupFormat::OPTION_GROUP_FORMAT,
1278                           LLDB_OPT_SET_1);
1279     m_option_group.Append(&m_format_options,
1280                           OptionGroupFormat::OPTION_GROUP_SIZE,
1281                           LLDB_OPT_SET_1 | LLDB_OPT_SET_2);
1282     m_option_group.Append(&m_memory_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_2);
1283     m_option_group.Finalize();
1284   }
1285 
1286   ~CommandObjectMemoryWrite() override = default;
1287 
1288   Options *GetOptions() override { return &m_option_group; }
1289 
1290   bool UIntValueIsValidForSize(uint64_t uval64, size_t total_byte_size) {
1291     if (total_byte_size > 8)
1292       return false;
1293 
1294     if (total_byte_size == 8)
1295       return true;
1296 
1297     const uint64_t max = ((uint64_t)1 << (uint64_t)(total_byte_size * 8)) - 1;
1298     return uval64 <= max;
1299   }
1300 
1301   bool SIntValueIsValidForSize(int64_t sval64, size_t total_byte_size) {
1302     if (total_byte_size > 8)
1303       return false;
1304 
1305     if (total_byte_size == 8)
1306       return true;
1307 
1308     const int64_t max = ((int64_t)1 << (uint64_t)(total_byte_size * 8 - 1)) - 1;
1309     const int64_t min = ~(max);
1310     return min <= sval64 && sval64 <= max;
1311   }
1312 
1313 protected:
1314   bool DoExecute(Args &command, CommandReturnObject &result) override {
1315     // No need to check "process" for validity as eCommandRequiresProcess
1316     // ensures it is valid
1317     Process *process = m_exe_ctx.GetProcessPtr();
1318 
1319     const size_t argc = command.GetArgumentCount();
1320 
1321     if (m_memory_options.m_infile) {
1322       if (argc < 1) {
1323         result.AppendErrorWithFormat(
1324             "%s takes a destination address when writing file contents.\n",
1325             m_cmd_name.c_str());
1326         result.SetStatus(eReturnStatusFailed);
1327         return false;
1328       }
1329     } else if (argc < 2) {
1330       result.AppendErrorWithFormat(
1331           "%s takes a destination address and at least one value.\n",
1332           m_cmd_name.c_str());
1333       result.SetStatus(eReturnStatusFailed);
1334       return false;
1335     }
1336 
1337     StreamString buffer(
1338         Stream::eBinary,
1339         process->GetTarget().GetArchitecture().GetAddressByteSize(),
1340         process->GetTarget().GetArchitecture().GetByteOrder());
1341 
1342     OptionValueUInt64 &byte_size_value = m_format_options.GetByteSizeValue();
1343     size_t item_byte_size = byte_size_value.GetCurrentValue();
1344 
1345     Status error;
1346     lldb::addr_t addr = OptionArgParser::ToAddress(
1347         &m_exe_ctx, command[0].ref, LLDB_INVALID_ADDRESS, &error);
1348 
1349     if (addr == LLDB_INVALID_ADDRESS) {
1350       result.AppendError("invalid address expression\n");
1351       result.AppendError(error.AsCString());
1352       result.SetStatus(eReturnStatusFailed);
1353       return false;
1354     }
1355 
1356     if (m_memory_options.m_infile) {
1357       size_t length = SIZE_MAX;
1358       if (item_byte_size > 1)
1359         length = item_byte_size;
1360       auto data_sp = FileSystem::Instance().CreateDataBuffer(
1361           m_memory_options.m_infile.GetPath(), length,
1362           m_memory_options.m_infile_offset);
1363       if (data_sp) {
1364         length = data_sp->GetByteSize();
1365         if (length > 0) {
1366           Status error;
1367           size_t bytes_written =
1368               process->WriteMemory(addr, data_sp->GetBytes(), length, error);
1369 
1370           if (bytes_written == length) {
1371             // All bytes written
1372             result.GetOutputStream().Printf(
1373                 "%" PRIu64 " bytes were written to 0x%" PRIx64 "\n",
1374                 (uint64_t)bytes_written, addr);
1375             result.SetStatus(eReturnStatusSuccessFinishResult);
1376           } else if (bytes_written > 0) {
1377             // Some byte written
1378             result.GetOutputStream().Printf(
1379                 "%" PRIu64 " bytes of %" PRIu64
1380                 " requested were written to 0x%" PRIx64 "\n",
1381                 (uint64_t)bytes_written, (uint64_t)length, addr);
1382             result.SetStatus(eReturnStatusSuccessFinishResult);
1383           } else {
1384             result.AppendErrorWithFormat("Memory write to 0x%" PRIx64
1385                                          " failed: %s.\n",
1386                                          addr, error.AsCString());
1387             result.SetStatus(eReturnStatusFailed);
1388           }
1389         }
1390       } else {
1391         result.AppendErrorWithFormat("Unable to read contents of file.\n");
1392         result.SetStatus(eReturnStatusFailed);
1393       }
1394       return result.Succeeded();
1395     } else if (item_byte_size == 0) {
1396       if (m_format_options.GetFormat() == eFormatPointer)
1397         item_byte_size = buffer.GetAddressByteSize();
1398       else
1399         item_byte_size = 1;
1400     }
1401 
1402     command.Shift(); // shift off the address argument
1403     uint64_t uval64;
1404     int64_t sval64;
1405     bool success = false;
1406     for (auto &entry : command) {
1407       switch (m_format_options.GetFormat()) {
1408       case kNumFormats:
1409       case eFormatFloat: // TODO: add support for floats soon
1410       case eFormatCharPrintable:
1411       case eFormatBytesWithASCII:
1412       case eFormatComplex:
1413       case eFormatEnum:
1414       case eFormatUnicode16:
1415       case eFormatUnicode32:
1416       case eFormatVectorOfChar:
1417       case eFormatVectorOfSInt8:
1418       case eFormatVectorOfUInt8:
1419       case eFormatVectorOfSInt16:
1420       case eFormatVectorOfUInt16:
1421       case eFormatVectorOfSInt32:
1422       case eFormatVectorOfUInt32:
1423       case eFormatVectorOfSInt64:
1424       case eFormatVectorOfUInt64:
1425       case eFormatVectorOfFloat16:
1426       case eFormatVectorOfFloat32:
1427       case eFormatVectorOfFloat64:
1428       case eFormatVectorOfUInt128:
1429       case eFormatOSType:
1430       case eFormatComplexInteger:
1431       case eFormatAddressInfo:
1432       case eFormatHexFloat:
1433       case eFormatInstruction:
1434       case eFormatVoid:
1435         result.AppendError("unsupported format for writing memory");
1436         result.SetStatus(eReturnStatusFailed);
1437         return false;
1438 
1439       case eFormatDefault:
1440       case eFormatBytes:
1441       case eFormatHex:
1442       case eFormatHexUppercase:
1443       case eFormatPointer:
1444       {
1445         // Decode hex bytes
1446         // Be careful, getAsInteger with a radix of 16 rejects "0xab" so we
1447         // have to special case that:
1448         bool success = false;
1449         if (entry.ref.startswith("0x"))
1450           success = !entry.ref.getAsInteger(0, uval64);
1451         if (!success)
1452           success = !entry.ref.getAsInteger(16, uval64);
1453         if (!success) {
1454           result.AppendErrorWithFormat(
1455               "'%s' is not a valid hex string value.\n", entry.c_str());
1456           result.SetStatus(eReturnStatusFailed);
1457           return false;
1458         } else if (!UIntValueIsValidForSize(uval64, item_byte_size)) {
1459           result.AppendErrorWithFormat("Value 0x%" PRIx64
1460                                        " is too large to fit in a %" PRIu64
1461                                        " byte unsigned integer value.\n",
1462                                        uval64, (uint64_t)item_byte_size);
1463           result.SetStatus(eReturnStatusFailed);
1464           return false;
1465         }
1466         buffer.PutMaxHex64(uval64, item_byte_size);
1467         break;
1468       }
1469       case eFormatBoolean:
1470         uval64 = OptionArgParser::ToBoolean(entry.ref, false, &success);
1471         if (!success) {
1472           result.AppendErrorWithFormat(
1473               "'%s' is not a valid boolean string value.\n", entry.c_str());
1474           result.SetStatus(eReturnStatusFailed);
1475           return false;
1476         }
1477         buffer.PutMaxHex64(uval64, item_byte_size);
1478         break;
1479 
1480       case eFormatBinary:
1481         if (entry.ref.getAsInteger(2, uval64)) {
1482           result.AppendErrorWithFormat(
1483               "'%s' is not a valid binary string value.\n", entry.c_str());
1484           result.SetStatus(eReturnStatusFailed);
1485           return false;
1486         } else if (!UIntValueIsValidForSize(uval64, item_byte_size)) {
1487           result.AppendErrorWithFormat("Value 0x%" PRIx64
1488                                        " is too large to fit in a %" PRIu64
1489                                        " byte unsigned integer value.\n",
1490                                        uval64, (uint64_t)item_byte_size);
1491           result.SetStatus(eReturnStatusFailed);
1492           return false;
1493         }
1494         buffer.PutMaxHex64(uval64, item_byte_size);
1495         break;
1496 
1497       case eFormatCharArray:
1498       case eFormatChar:
1499       case eFormatCString: {
1500         if (entry.ref.empty())
1501           break;
1502 
1503         size_t len = entry.ref.size();
1504         // Include the NULL for C strings...
1505         if (m_format_options.GetFormat() == eFormatCString)
1506           ++len;
1507         Status error;
1508         if (process->WriteMemory(addr, entry.c_str(), len, error) == len) {
1509           addr += len;
1510         } else {
1511           result.AppendErrorWithFormat("Memory write to 0x%" PRIx64
1512                                        " failed: %s.\n",
1513                                        addr, error.AsCString());
1514           result.SetStatus(eReturnStatusFailed);
1515           return false;
1516         }
1517         break;
1518       }
1519       case eFormatDecimal:
1520         if (entry.ref.getAsInteger(0, sval64)) {
1521           result.AppendErrorWithFormat(
1522               "'%s' is not a valid signed decimal value.\n", entry.c_str());
1523           result.SetStatus(eReturnStatusFailed);
1524           return false;
1525         } else if (!SIntValueIsValidForSize(sval64, item_byte_size)) {
1526           result.AppendErrorWithFormat(
1527               "Value %" PRIi64 " is too large or small to fit in a %" PRIu64
1528               " byte signed integer value.\n",
1529               sval64, (uint64_t)item_byte_size);
1530           result.SetStatus(eReturnStatusFailed);
1531           return false;
1532         }
1533         buffer.PutMaxHex64(sval64, item_byte_size);
1534         break;
1535 
1536       case eFormatUnsigned:
1537 
1538         if (!entry.ref.getAsInteger(0, uval64)) {
1539           result.AppendErrorWithFormat(
1540               "'%s' is not a valid unsigned decimal string value.\n",
1541               entry.c_str());
1542           result.SetStatus(eReturnStatusFailed);
1543           return false;
1544         } else if (!UIntValueIsValidForSize(uval64, item_byte_size)) {
1545           result.AppendErrorWithFormat("Value %" PRIu64
1546                                        " is too large to fit in a %" PRIu64
1547                                        " byte unsigned integer value.\n",
1548                                        uval64, (uint64_t)item_byte_size);
1549           result.SetStatus(eReturnStatusFailed);
1550           return false;
1551         }
1552         buffer.PutMaxHex64(uval64, item_byte_size);
1553         break;
1554 
1555       case eFormatOctal:
1556         if (entry.ref.getAsInteger(8, uval64)) {
1557           result.AppendErrorWithFormat(
1558               "'%s' is not a valid octal string value.\n", entry.c_str());
1559           result.SetStatus(eReturnStatusFailed);
1560           return false;
1561         } else if (!UIntValueIsValidForSize(uval64, item_byte_size)) {
1562           result.AppendErrorWithFormat("Value %" PRIo64
1563                                        " is too large to fit in a %" PRIu64
1564                                        " byte unsigned integer value.\n",
1565                                        uval64, (uint64_t)item_byte_size);
1566           result.SetStatus(eReturnStatusFailed);
1567           return false;
1568         }
1569         buffer.PutMaxHex64(uval64, item_byte_size);
1570         break;
1571       }
1572     }
1573 
1574     if (!buffer.GetString().empty()) {
1575       Status error;
1576       if (process->WriteMemory(addr, buffer.GetString().data(),
1577                                buffer.GetString().size(),
1578                                error) == buffer.GetString().size())
1579         return true;
1580       else {
1581         result.AppendErrorWithFormat("Memory write to 0x%" PRIx64
1582                                      " failed: %s.\n",
1583                                      addr, error.AsCString());
1584         result.SetStatus(eReturnStatusFailed);
1585         return false;
1586       }
1587     }
1588     return true;
1589   }
1590 
1591   OptionGroupOptions m_option_group;
1592   OptionGroupFormat m_format_options;
1593   OptionGroupWriteMemory m_memory_options;
1594 };
1595 
1596 // Get malloc/free history of a memory address.
1597 class CommandObjectMemoryHistory : public CommandObjectParsed {
1598 public:
1599   CommandObjectMemoryHistory(CommandInterpreter &interpreter)
1600       : CommandObjectParsed(
1601             interpreter, "memory history", "Print recorded stack traces for "
1602                                            "allocation/deallocation events "
1603                                            "associated with an address.",
1604             nullptr,
1605             eCommandRequiresTarget | eCommandRequiresProcess |
1606                 eCommandProcessMustBePaused | eCommandProcessMustBeLaunched) {
1607     CommandArgumentEntry arg1;
1608     CommandArgumentData addr_arg;
1609 
1610     // Define the first (and only) variant of this arg.
1611     addr_arg.arg_type = eArgTypeAddress;
1612     addr_arg.arg_repetition = eArgRepeatPlain;
1613 
1614     // There is only one variant this argument could be; put it into the
1615     // argument entry.
1616     arg1.push_back(addr_arg);
1617 
1618     // Push the data for the first argument into the m_arguments vector.
1619     m_arguments.push_back(arg1);
1620   }
1621 
1622   ~CommandObjectMemoryHistory() override = default;
1623 
1624   const char *GetRepeatCommand(Args &current_command_args,
1625                                uint32_t index) override {
1626     return m_cmd_name.c_str();
1627   }
1628 
1629 protected:
1630   bool DoExecute(Args &command, CommandReturnObject &result) override {
1631     const size_t argc = command.GetArgumentCount();
1632 
1633     if (argc == 0 || argc > 1) {
1634       result.AppendErrorWithFormat("%s takes an address expression",
1635                                    m_cmd_name.c_str());
1636       result.SetStatus(eReturnStatusFailed);
1637       return false;
1638     }
1639 
1640     Status error;
1641     lldb::addr_t addr = OptionArgParser::ToAddress(
1642         &m_exe_ctx, command[0].ref, LLDB_INVALID_ADDRESS, &error);
1643 
1644     if (addr == LLDB_INVALID_ADDRESS) {
1645       result.AppendError("invalid address expression");
1646       result.AppendError(error.AsCString());
1647       result.SetStatus(eReturnStatusFailed);
1648       return false;
1649     }
1650 
1651     Stream *output_stream = &result.GetOutputStream();
1652 
1653     const ProcessSP &process_sp = m_exe_ctx.GetProcessSP();
1654     const MemoryHistorySP &memory_history =
1655         MemoryHistory::FindPlugin(process_sp);
1656 
1657     if (!memory_history) {
1658       result.AppendError("no available memory history provider");
1659       result.SetStatus(eReturnStatusFailed);
1660       return false;
1661     }
1662 
1663     HistoryThreads thread_list = memory_history->GetHistoryThreads(addr);
1664 
1665     const bool stop_format = false;
1666     for (auto thread : thread_list) {
1667       thread->GetStatus(*output_stream, 0, UINT32_MAX, 0, stop_format);
1668     }
1669 
1670     result.SetStatus(eReturnStatusSuccessFinishResult);
1671 
1672     return true;
1673   }
1674 };
1675 
1676 // CommandObjectMemoryRegion
1677 #pragma mark CommandObjectMemoryRegion
1678 
1679 class CommandObjectMemoryRegion : public CommandObjectParsed {
1680 public:
1681   CommandObjectMemoryRegion(CommandInterpreter &interpreter)
1682       : CommandObjectParsed(interpreter, "memory region",
1683                             "Get information on the memory region containing "
1684                             "an address in the current target process.",
1685                             "memory region ADDR",
1686                             eCommandRequiresProcess | eCommandTryTargetAPILock |
1687                                 eCommandProcessMustBeLaunched),
1688         m_prev_end_addr(LLDB_INVALID_ADDRESS) {}
1689 
1690   ~CommandObjectMemoryRegion() override = default;
1691 
1692 protected:
1693   bool DoExecute(Args &command, CommandReturnObject &result) override {
1694     ProcessSP process_sp = m_exe_ctx.GetProcessSP();
1695     if (process_sp) {
1696       Status error;
1697       lldb::addr_t load_addr = m_prev_end_addr;
1698       m_prev_end_addr = LLDB_INVALID_ADDRESS;
1699 
1700       const size_t argc = command.GetArgumentCount();
1701       if (argc > 1 || (argc == 0 && load_addr == LLDB_INVALID_ADDRESS)) {
1702         result.AppendErrorWithFormat("'%s' takes one argument:\nUsage: %s\n",
1703                                      m_cmd_name.c_str(), m_cmd_syntax.c_str());
1704         result.SetStatus(eReturnStatusFailed);
1705       } else {
1706         if (command.GetArgumentCount() == 1) {
1707           auto load_addr_str = command[0].ref;
1708           load_addr = OptionArgParser::ToAddress(&m_exe_ctx, load_addr_str,
1709                                                  LLDB_INVALID_ADDRESS, &error);
1710           if (error.Fail() || load_addr == LLDB_INVALID_ADDRESS) {
1711             result.AppendErrorWithFormat(
1712                 "invalid address argument \"%s\": %s\n", command[0].c_str(),
1713                 error.AsCString());
1714             result.SetStatus(eReturnStatusFailed);
1715           }
1716         }
1717 
1718         lldb_private::MemoryRegionInfo range_info;
1719         error = process_sp->GetMemoryRegionInfo(load_addr, range_info);
1720         if (error.Success()) {
1721           lldb_private::Address addr;
1722           ConstString name = range_info.GetName();
1723           ConstString section_name;
1724           if (process_sp->GetTarget().ResolveLoadAddress(load_addr, addr)) {
1725             SectionSP section_sp(addr.GetSection());
1726             if (section_sp) {
1727               // Got the top most section, not the deepest section
1728               while (section_sp->GetParent())
1729                 section_sp = section_sp->GetParent();
1730               section_name = section_sp->GetName();
1731             }
1732           }
1733           result.AppendMessageWithFormat(
1734               "[0x%16.16" PRIx64 "-0x%16.16" PRIx64 ") %c%c%c%s%s%s%s\n",
1735               range_info.GetRange().GetRangeBase(),
1736               range_info.GetRange().GetRangeEnd(),
1737               range_info.GetReadable() ? 'r' : '-',
1738               range_info.GetWritable() ? 'w' : '-',
1739               range_info.GetExecutable() ? 'x' : '-',
1740               name ? " " : "", name.AsCString(""),
1741               section_name ? " " : "", section_name.AsCString(""));
1742           m_prev_end_addr = range_info.GetRange().GetRangeEnd();
1743           result.SetStatus(eReturnStatusSuccessFinishResult);
1744         } else {
1745           result.SetStatus(eReturnStatusFailed);
1746           result.AppendErrorWithFormat("%s\n", error.AsCString());
1747         }
1748       }
1749     } else {
1750       m_prev_end_addr = LLDB_INVALID_ADDRESS;
1751       result.AppendError("invalid process");
1752       result.SetStatus(eReturnStatusFailed);
1753     }
1754     return result.Succeeded();
1755   }
1756 
1757   const char *GetRepeatCommand(Args &current_command_args,
1758                                uint32_t index) override {
1759     // If we repeat this command, repeat it without any arguments so we can
1760     // show the next memory range
1761     return m_cmd_name.c_str();
1762   }
1763 
1764   lldb::addr_t m_prev_end_addr;
1765 };
1766 
1767 // CommandObjectMemory
1768 
1769 CommandObjectMemory::CommandObjectMemory(CommandInterpreter &interpreter)
1770     : CommandObjectMultiword(
1771           interpreter, "memory",
1772           "Commands for operating on memory in the current target process.",
1773           "memory <subcommand> [<subcommand-options>]") {
1774   LoadSubCommand("find",
1775                  CommandObjectSP(new CommandObjectMemoryFind(interpreter)));
1776   LoadSubCommand("read",
1777                  CommandObjectSP(new CommandObjectMemoryRead(interpreter)));
1778   LoadSubCommand("write",
1779                  CommandObjectSP(new CommandObjectMemoryWrite(interpreter)));
1780   LoadSubCommand("history",
1781                  CommandObjectSP(new CommandObjectMemoryHistory(interpreter)));
1782   LoadSubCommand("region",
1783                  CommandObjectSP(new CommandObjectMemoryRegion(interpreter)));
1784 }
1785 
1786 CommandObjectMemory::~CommandObjectMemory() = default;
1787