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