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