xref: /llvm-project/lldb/source/Commands/CommandObjectMemory.cpp (revision c33ae024a64962cb38b64073a035a5fc36aa2214)
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/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     virtual
71     ~OptionGroupReadMemory ()
72     {
73     }
74 
75 
76     virtual uint32_t
77     GetNumDefinitions ()
78     {
79         return sizeof (g_option_table) / sizeof (OptionDefinition);
80     }
81 
82     virtual const OptionDefinition*
83     GetDefinitions ()
84     {
85         return g_option_table;
86     }
87 
88     virtual Error
89     SetOptionValue (CommandInterpreter &interpreter,
90                     uint32_t option_idx,
91                     const char *option_arg)
92     {
93         Error error;
94         const int short_option = g_option_table[option_idx].short_option;
95 
96         switch (short_option)
97         {
98             case 'l':
99                 error = m_num_per_line.SetValueFromString (option_arg);
100                 if (m_num_per_line.GetCurrentValue() == 0)
101                     error.SetErrorStringWithFormat("invalid value for --num-per-line option '%s'", option_arg);
102                 break;
103 
104             case 'b':
105                 m_output_as_binary = true;
106                 break;
107 
108             case 't':
109                 error = m_view_as_type.SetValueFromString (option_arg);
110                 break;
111 
112             case 'r':
113                 m_force = true;
114                 break;
115 
116             default:
117                 error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
118                 break;
119         }
120         return error;
121     }
122 
123     virtual void
124     OptionParsingStarting (CommandInterpreter &interpreter)
125     {
126         m_num_per_line.Clear();
127         m_output_as_binary = false;
128         m_view_as_type.Clear();
129         m_force = false;
130     }
131 
132     Error
133     FinalizeSettings (Target *target, OptionGroupFormat& format_options)
134     {
135         Error error;
136         OptionValueUInt64 &byte_size_value = format_options.GetByteSizeValue();
137         OptionValueUInt64 &count_value = format_options.GetCountValue();
138         const bool byte_size_option_set = byte_size_value.OptionWasSet();
139         const bool num_per_line_option_set = m_num_per_line.OptionWasSet();
140         const bool count_option_set = format_options.GetCountValue().OptionWasSet();
141 
142         switch (format_options.GetFormat())
143         {
144             default:
145                 break;
146 
147             case eFormatBoolean:
148                 if (!byte_size_option_set)
149                     byte_size_value = 1;
150                 if (!num_per_line_option_set)
151                     m_num_per_line = 1;
152                 if (!count_option_set)
153                     format_options.GetCountValue() = 8;
154                 break;
155 
156             case eFormatCString:
157                 break;
158 
159             case eFormatInstruction:
160                 if (count_option_set)
161                     byte_size_value = target->GetArchitecture().GetMaximumOpcodeByteSize();
162                 m_num_per_line = 1;
163                 break;
164 
165             case eFormatAddressInfo:
166                 if (!byte_size_option_set)
167                     byte_size_value = target->GetArchitecture().GetAddressByteSize();
168                 m_num_per_line = 1;
169                 if (!count_option_set)
170                     format_options.GetCountValue() = 8;
171                 break;
172 
173             case eFormatPointer:
174                 byte_size_value = target->GetArchitecture().GetAddressByteSize();
175                 if (!num_per_line_option_set)
176                     m_num_per_line = 4;
177                 if (!count_option_set)
178                     format_options.GetCountValue() = 8;
179                 break;
180 
181             case eFormatBinary:
182             case eFormatFloat:
183             case eFormatOctal:
184             case eFormatDecimal:
185             case eFormatEnum:
186             case eFormatUnicode16:
187             case eFormatUnicode32:
188             case eFormatUnsigned:
189             case eFormatHexFloat:
190                 if (!byte_size_option_set)
191                     byte_size_value = 4;
192                 if (!num_per_line_option_set)
193                     m_num_per_line = 1;
194                 if (!count_option_set)
195                     format_options.GetCountValue() = 8;
196                 break;
197 
198             case eFormatBytes:
199             case eFormatBytesWithASCII:
200                 if (byte_size_option_set)
201                 {
202                     if (byte_size_value > 1)
203                         error.SetErrorStringWithFormat ("display format (bytes/bytes with ascii) conflicts with the specified byte size %" PRIu64 "\n"
204                                                         "\tconsider using a different display format or don't specify the byte size",
205                                                         byte_size_value.GetCurrentValue());
206                 }
207                 else
208                     byte_size_value = 1;
209                 if (!num_per_line_option_set)
210                     m_num_per_line = 16;
211                 if (!count_option_set)
212                     format_options.GetCountValue() = 32;
213                 break;
214             case eFormatCharArray:
215             case eFormatChar:
216             case eFormatCharPrintable:
217                 if (!byte_size_option_set)
218                     byte_size_value = 1;
219                 if (!num_per_line_option_set)
220                     m_num_per_line = 32;
221                 if (!count_option_set)
222                     format_options.GetCountValue() = 64;
223                 break;
224             case eFormatComplex:
225                 if (!byte_size_option_set)
226                     byte_size_value = 8;
227                 if (!num_per_line_option_set)
228                     m_num_per_line = 1;
229                 if (!count_option_set)
230                     format_options.GetCountValue() = 8;
231                 break;
232             case eFormatComplexInteger:
233                 if (!byte_size_option_set)
234                     byte_size_value = 8;
235                 if (!num_per_line_option_set)
236                     m_num_per_line = 1;
237                 if (!count_option_set)
238                     format_options.GetCountValue() = 8;
239                 break;
240             case eFormatHex:
241                 if (!byte_size_option_set)
242                     byte_size_value = 4;
243                 if (!num_per_line_option_set)
244                 {
245                     switch (byte_size_value)
246                     {
247                         case 1:
248                         case 2:
249                             m_num_per_line = 8;
250                             break;
251                         case 4:
252                             m_num_per_line = 4;
253                             break;
254                         case 8:
255                             m_num_per_line = 2;
256                             break;
257                         default:
258                             m_num_per_line = 1;
259                             break;
260                     }
261                 }
262                 if (!count_option_set)
263                     count_value = 8;
264                 break;
265 
266             case eFormatVectorOfChar:
267             case eFormatVectorOfSInt8:
268             case eFormatVectorOfUInt8:
269             case eFormatVectorOfSInt16:
270             case eFormatVectorOfUInt16:
271             case eFormatVectorOfSInt32:
272             case eFormatVectorOfUInt32:
273             case eFormatVectorOfSInt64:
274             case eFormatVectorOfUInt64:
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     virtual
371     ~CommandObjectMemoryRead ()
372     {
373     }
374 
375     Options *
376     GetOptions ()
377     {
378         return &m_option_group;
379     }
380 
381     virtual const char *GetRepeatCommand (Args &current_command_args, uint32_t index)
382     {
383         return m_cmd_name.c_str();
384     }
385 
386 protected:
387     virtual bool
388     DoExecute (Args& command, CommandReturnObject &result)
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         ClangASTType 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                 clang::TypeDecl *tdecl = target->GetPersistentVariables().GetPersistentType(ConstString(lookup_type_name));
534                 if (tdecl)
535                 {
536                     clang_ast_type.SetClangType(ClangASTContext::GetASTContext(&tdecl->getASTContext()),(const lldb::clang_type_t)tdecl->getTypeForDecl());
537                 }
538             }
539 
540             if (clang_ast_type.IsValid() == false)
541             {
542                 if (type_list.GetSize() == 0)
543                 {
544                     result.AppendErrorWithFormat ("unable to find any types that match the raw type '%s' for full type '%s'\n",
545                                                   lookup_type_name.GetCString(),
546                                                   view_as_type_cstr);
547                     result.SetStatus(eReturnStatusFailed);
548                     return false;
549                 }
550                 else
551                 {
552                     TypeSP type_sp (type_list.GetTypeAtIndex(0));
553                     clang_ast_type = type_sp->GetClangFullType();
554                 }
555             }
556 
557             while (pointer_count > 0)
558             {
559                 ClangASTType pointer_type = clang_ast_type.GetPointerType();
560                 if (pointer_type.IsValid())
561                     clang_ast_type = pointer_type;
562                 else
563                 {
564                     result.AppendError ("unable make a pointer type\n");
565                     result.SetStatus(eReturnStatusFailed);
566                     return false;
567                 }
568                 --pointer_count;
569             }
570 
571             m_format_options.GetByteSizeValue() = clang_ast_type.GetByteSize(nullptr);
572 
573             if (m_format_options.GetByteSizeValue() == 0)
574             {
575                 result.AppendErrorWithFormat ("unable to get the byte size of the type '%s'\n",
576                                               view_as_type_cstr);
577                 result.SetStatus(eReturnStatusFailed);
578                 return false;
579             }
580 
581             if (!m_format_options.GetCountValue().OptionWasSet())
582                 m_format_options.GetCountValue() = 1;
583         }
584         else
585         {
586             error = m_memory_options.FinalizeSettings (target, m_format_options);
587         }
588 
589         // Look for invalid combinations of settings
590         if (error.Fail())
591         {
592             result.AppendError(error.AsCString());
593             result.SetStatus(eReturnStatusFailed);
594             return false;
595         }
596 
597         lldb::addr_t addr;
598         size_t total_byte_size = 0;
599         if (argc == 0)
600         {
601             // Use the last address and byte size and all options as they were
602             // if no options have been set
603             addr = m_next_addr;
604             total_byte_size = m_prev_byte_size;
605             clang_ast_type = m_prev_clang_ast_type;
606             if (!m_format_options.AnyOptionWasSet() &&
607                 !m_memory_options.AnyOptionWasSet() &&
608                 !m_outfile_options.AnyOptionWasSet() &&
609                 !m_varobj_options.AnyOptionWasSet())
610             {
611                 m_format_options = m_prev_format_options;
612                 m_memory_options = m_prev_memory_options;
613                 m_outfile_options = m_prev_outfile_options;
614                 m_varobj_options = m_prev_varobj_options;
615             }
616         }
617 
618         size_t item_count = m_format_options.GetCountValue().GetCurrentValue();
619 
620         // TODO For non-8-bit byte addressable architectures this needs to be
621         // revisited to fully support all lldb's range of formatting options.
622         // Furthermore code memory reads (for those architectures) will not
623         // be correctly formatted even w/o formatting options.
624         size_t item_byte_size =
625             target->GetArchitecture().GetDataByteSize() > 1 ?
626             target->GetArchitecture().GetDataByteSize() :
627             m_format_options.GetByteSizeValue().GetCurrentValue();
628 
629         const size_t num_per_line = m_memory_options.m_num_per_line.GetCurrentValue();
630 
631         if (total_byte_size == 0)
632         {
633             total_byte_size = item_count * item_byte_size;
634             if (total_byte_size == 0)
635                 total_byte_size = 32;
636         }
637 
638         if (argc > 0)
639             addr = Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, &error);
640 
641         if (addr == LLDB_INVALID_ADDRESS)
642         {
643             result.AppendError("invalid start address expression.");
644             result.AppendError(error.AsCString());
645             result.SetStatus(eReturnStatusFailed);
646             return false;
647         }
648 
649         if (argc == 2)
650         {
651             lldb::addr_t end_addr = Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(1), LLDB_INVALID_ADDRESS, 0);
652             if (end_addr == LLDB_INVALID_ADDRESS)
653             {
654                 result.AppendError("invalid end address expression.");
655                 result.AppendError(error.AsCString());
656                 result.SetStatus(eReturnStatusFailed);
657                 return false;
658             }
659             else if (end_addr <= addr)
660             {
661                 result.AppendErrorWithFormat("end address (0x%" PRIx64 ") must be greater that the start address (0x%" PRIx64 ").\n", end_addr, addr);
662                 result.SetStatus(eReturnStatusFailed);
663                 return false;
664             }
665             else if (m_format_options.GetCountValue().OptionWasSet())
666             {
667                 result.AppendErrorWithFormat("specify either the end address (0x%" PRIx64 ") or the count (--count %" PRIu64 "), not both.\n", end_addr, (uint64_t)item_count);
668                 result.SetStatus(eReturnStatusFailed);
669                 return false;
670             }
671 
672             total_byte_size = end_addr - addr;
673             item_count = total_byte_size / item_byte_size;
674         }
675 
676         uint32_t max_unforced_size = target->GetMaximumMemReadSize();
677 
678         if (total_byte_size > max_unforced_size && !m_memory_options.m_force)
679         {
680             result.AppendErrorWithFormat("Normally, \'memory read\' will not read over %" PRIu32 " bytes of data.\n",max_unforced_size);
681             result.AppendErrorWithFormat("Please use --force to override this restriction just once.\n");
682             result.AppendErrorWithFormat("or set target.max-memory-read-size if you will often need a larger limit.\n");
683             return false;
684         }
685 
686         DataBufferSP data_sp;
687         size_t bytes_read = 0;
688         if (clang_ast_type.GetOpaqueQualType())
689         {
690             // Make sure we don't display our type as ASCII bytes like the default memory read
691             if (m_format_options.GetFormatValue().OptionWasSet() == false)
692                 m_format_options.GetFormatValue().SetCurrentValue(eFormatDefault);
693 
694             bytes_read = clang_ast_type.GetByteSize(nullptr) * m_format_options.GetCountValue().GetCurrentValue();
695         }
696         else if (m_format_options.GetFormatValue().GetCurrentValue() != eFormatCString)
697         {
698             data_sp.reset (new DataBufferHeap (total_byte_size, '\0'));
699             if (data_sp->GetBytes() == NULL)
700             {
701                 result.AppendErrorWithFormat ("can't allocate 0x%" PRIx32 " bytes for the memory read buffer, specify a smaller size to read", (uint32_t)total_byte_size);
702                 result.SetStatus(eReturnStatusFailed);
703                 return false;
704             }
705 
706             Address address(addr, NULL);
707             bytes_read = target->ReadMemory(address, false, data_sp->GetBytes (), data_sp->GetByteSize(), error);
708             if (bytes_read == 0)
709             {
710                 const char *error_cstr = error.AsCString();
711                 if (error_cstr && error_cstr[0])
712                 {
713                     result.AppendError(error_cstr);
714                 }
715                 else
716                 {
717                     result.AppendErrorWithFormat("failed to read memory from 0x%" PRIx64 ".\n", addr);
718                 }
719                 result.SetStatus(eReturnStatusFailed);
720                 return false;
721             }
722 
723             if (bytes_read < total_byte_size)
724                 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);
725         }
726         else
727         {
728             // we treat c-strings as a special case because they do not have a fixed size
729             if (m_format_options.GetByteSizeValue().OptionWasSet() && !m_format_options.HasGDBFormat())
730                 item_byte_size = m_format_options.GetByteSizeValue().GetCurrentValue();
731             else
732                 item_byte_size = target->GetMaximumSizeOfStringSummary();
733             if (!m_format_options.GetCountValue().OptionWasSet())
734                 item_count = 1;
735             data_sp.reset (new DataBufferHeap ((item_byte_size+1) * item_count, '\0')); // account for NULLs as necessary
736             if (data_sp->GetBytes() == NULL)
737             {
738                 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));
739                 result.SetStatus(eReturnStatusFailed);
740                 return false;
741             }
742             uint8_t *data_ptr = data_sp->GetBytes();
743             auto data_addr = addr;
744             auto count = item_count;
745             item_count = 0;
746             bool break_on_no_NULL = false;
747             while (item_count < count)
748             {
749                 std::string buffer;
750                 buffer.resize(item_byte_size+1,0);
751                 Error error;
752                 size_t read = target->ReadCStringFromMemory(data_addr, &buffer[0], item_byte_size+1, error);
753                 if (error.Fail())
754                 {
755                     result.AppendErrorWithFormat("failed to read memory from 0x%" PRIx64 ".\n", addr);
756                     result.SetStatus(eReturnStatusFailed);
757                     return false;
758                 }
759 
760                 if (item_byte_size == read)
761                 {
762                     result.AppendWarningWithFormat("unable to find a NULL terminated string at 0x%" PRIx64 ".Consider increasing the maximum read length.\n", data_addr);
763                     --read;
764                     break_on_no_NULL = true;
765                 }
766                 else
767                     ++read; // account for final NULL byte
768 
769                 memcpy(data_ptr, &buffer[0], read);
770                 data_ptr += read;
771                 data_addr += read;
772                 bytes_read += read;
773                 item_count++; // if we break early we know we only read item_count strings
774 
775                 if (break_on_no_NULL)
776                     break;
777             }
778             data_sp.reset(new DataBufferHeap(data_sp->GetBytes(),bytes_read+1));
779         }
780 
781         m_next_addr = addr + bytes_read;
782         m_prev_byte_size = bytes_read;
783         m_prev_format_options = m_format_options;
784         m_prev_memory_options = m_memory_options;
785         m_prev_outfile_options = m_outfile_options;
786         m_prev_varobj_options = m_varobj_options;
787         m_prev_clang_ast_type = clang_ast_type;
788 
789         StreamFile outfile_stream;
790         Stream *output_stream = NULL;
791         const FileSpec &outfile_spec = m_outfile_options.GetFile().GetCurrentValue();
792         if (outfile_spec)
793         {
794             char path[PATH_MAX];
795             outfile_spec.GetPath (path, sizeof(path));
796 
797             uint32_t open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate;
798             const bool append = m_outfile_options.GetAppend().GetCurrentValue();
799             if (append)
800                 open_options |= File::eOpenOptionAppend;
801 
802             if (outfile_stream.GetFile ().Open (path, open_options).Success())
803             {
804                 if (m_memory_options.m_output_as_binary)
805                 {
806                     const size_t bytes_written = outfile_stream.Write (data_sp->GetBytes(), bytes_read);
807                     if (bytes_written > 0)
808                     {
809                         result.GetOutputStream().Printf ("%zi bytes %s to '%s'\n",
810                                                          bytes_written,
811                                                          append ? "appended" : "written",
812                                                          path);
813                         return true;
814                     }
815                     else
816                     {
817                         result.AppendErrorWithFormat("Failed to write %" PRIu64 " bytes to '%s'.\n", (uint64_t)bytes_read, path);
818                         result.SetStatus(eReturnStatusFailed);
819                         return false;
820                     }
821                 }
822                 else
823                 {
824                     // We are going to write ASCII to the file just point the
825                     // output_stream to our outfile_stream...
826                     output_stream = &outfile_stream;
827                 }
828             }
829             else
830             {
831                 result.AppendErrorWithFormat("Failed to open file '%s' for %s.\n", path, append ? "append" : "write");
832                 result.SetStatus(eReturnStatusFailed);
833                 return false;
834             }
835         }
836         else
837         {
838             output_stream = &result.GetOutputStream();
839         }
840 
841 
842         ExecutionContextScope *exe_scope = m_exe_ctx.GetBestExecutionContextScope();
843         if (clang_ast_type.GetOpaqueQualType())
844         {
845             for (uint32_t i = 0; i<item_count; ++i)
846             {
847                 addr_t item_addr = addr + (i * item_byte_size);
848                 Address address (item_addr);
849                 StreamString name_strm;
850                 name_strm.Printf ("0x%" PRIx64, item_addr);
851                 ValueObjectSP valobj_sp (ValueObjectMemory::Create (exe_scope,
852                                                                     name_strm.GetString().c_str(),
853                                                                     address,
854                                                                     clang_ast_type));
855                 if (valobj_sp)
856                 {
857                     Format format = m_format_options.GetFormat();
858                     if (format != eFormatDefault)
859                         valobj_sp->SetFormat (format);
860 
861                     DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(eLanguageRuntimeDescriptionDisplayVerbosityFull,format));
862 
863                     valobj_sp->Dump(*output_stream,options);
864                 }
865                 else
866                 {
867                     result.AppendErrorWithFormat ("failed to create a value object for: (%s) %s\n",
868                                                   view_as_type_cstr,
869                                                   name_strm.GetString().c_str());
870                     result.SetStatus(eReturnStatusFailed);
871                     return false;
872                 }
873             }
874             return true;
875         }
876 
877         result.SetStatus(eReturnStatusSuccessFinishResult);
878         DataExtractor data (data_sp,
879                             target->GetArchitecture().GetByteOrder(),
880                             target->GetArchitecture().GetAddressByteSize(),
881                             target->GetArchitecture().GetDataByteSize());
882 
883         Format format = m_format_options.GetFormat();
884         if ( ( (format == eFormatChar) || (format == eFormatCharPrintable) )
885             && (item_byte_size != 1))
886         {
887             // if a count was not passed, or it is 1
888             if (m_format_options.GetCountValue().OptionWasSet() == false || item_count == 1)
889             {
890                 // this turns requests such as
891                 // memory read -fc -s10 -c1 *charPtrPtr
892                 // which make no sense (what is a char of size 10?)
893                 // into a request for fetching 10 chars of size 1 from the same memory location
894                 format = eFormatCharArray;
895                 item_count = item_byte_size;
896                 item_byte_size = 1;
897             }
898             else
899             {
900                 // here we passed a count, and it was not 1
901                 // so we have a byte_size and a count
902                 // we could well multiply those, but instead let's just fail
903                 result.AppendErrorWithFormat("reading memory as characters of size %" PRIu64 " is not supported", (uint64_t)item_byte_size);
904                 result.SetStatus(eReturnStatusFailed);
905                 return false;
906             }
907         }
908 
909         assert (output_stream);
910         size_t bytes_dumped = data.Dump (output_stream,
911                                          0,
912                                          format,
913                                          item_byte_size,
914                                          item_count,
915                                          num_per_line / target->GetArchitecture().GetDataByteSize(),
916                                          addr,
917                                          0,
918                                          0,
919                                          exe_scope);
920         m_next_addr = addr + bytes_dumped;
921         output_stream->EOL();
922         return true;
923     }
924 
925     OptionGroupOptions m_option_group;
926     OptionGroupFormat m_format_options;
927     OptionGroupReadMemory m_memory_options;
928     OptionGroupOutputFile m_outfile_options;
929     OptionGroupValueObjectDisplay m_varobj_options;
930     lldb::addr_t m_next_addr;
931     lldb::addr_t m_prev_byte_size;
932     OptionGroupFormat m_prev_format_options;
933     OptionGroupReadMemory m_prev_memory_options;
934     OptionGroupOutputFile m_prev_outfile_options;
935     OptionGroupValueObjectDisplay m_prev_varobj_options;
936     ClangASTType m_prev_clang_ast_type;
937 };
938 
939 OptionDefinition
940 g_memory_find_option_table[] =
941 {
942     { LLDB_OPT_SET_1, false, "expression", 'e', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeExpression, "Evaluate an expression to obtain a byte pattern."},
943     { LLDB_OPT_SET_2, false, "string", 's', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeName,   "Use text to find a byte pattern."},
944     { LLDB_OPT_SET_1|LLDB_OPT_SET_2, false, "count", 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeCount,   "How many times to perform the search."},
945     { 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."},
946 };
947 
948 //----------------------------------------------------------------------
949 // Find the specified data in memory
950 //----------------------------------------------------------------------
951 class CommandObjectMemoryFind : public CommandObjectParsed
952 {
953 public:
954 
955   class OptionGroupFindMemory : public OptionGroup
956   {
957   public:
958     OptionGroupFindMemory () :
959       OptionGroup(),
960       m_count(1),
961       m_offset(0)
962     {
963     }
964 
965     virtual
966     ~OptionGroupFindMemory ()
967     {
968     }
969 
970     virtual uint32_t
971     GetNumDefinitions ()
972     {
973       return sizeof (g_memory_find_option_table) / sizeof (OptionDefinition);
974     }
975 
976     virtual const OptionDefinition*
977     GetDefinitions ()
978     {
979       return g_memory_find_option_table;
980     }
981 
982     virtual Error
983     SetOptionValue (CommandInterpreter &interpreter,
984                     uint32_t option_idx,
985                     const char *option_arg)
986     {
987         Error error;
988         const int short_option = g_memory_find_option_table[option_idx].short_option;
989 
990         switch (short_option)
991         {
992         case 'e':
993               m_expr.SetValueFromString(option_arg);
994               break;
995 
996         case 's':
997               m_string.SetValueFromString(option_arg);
998               break;
999 
1000         case 'c':
1001               if (m_count.SetValueFromString(option_arg).Fail())
1002                   error.SetErrorString("unrecognized value for count");
1003               break;
1004 
1005         case 'o':
1006                if (m_offset.SetValueFromString(option_arg).Fail())
1007                    error.SetErrorString("unrecognized value for dump-offset");
1008                 break;
1009 
1010         default:
1011               error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
1012               break;
1013         }
1014         return error;
1015     }
1016 
1017     virtual void
1018     OptionParsingStarting (CommandInterpreter &interpreter)
1019     {
1020         m_expr.Clear();
1021         m_string.Clear();
1022         m_count.Clear();
1023     }
1024 
1025       OptionValueString m_expr;
1026       OptionValueString m_string;
1027       OptionValueUInt64 m_count;
1028       OptionValueUInt64 m_offset;
1029   };
1030 
1031   CommandObjectMemoryFind (CommandInterpreter &interpreter) :
1032   CommandObjectParsed (interpreter,
1033                        "memory find",
1034                        "Find a value in the memory of the process being debugged.",
1035                        NULL,
1036                        eCommandRequiresProcess | eCommandProcessMustBeLaunched),
1037   m_option_group (interpreter),
1038   m_memory_options ()
1039   {
1040     CommandArgumentEntry arg1;
1041     CommandArgumentEntry arg2;
1042     CommandArgumentData addr_arg;
1043     CommandArgumentData value_arg;
1044 
1045     // Define the first (and only) variant of this arg.
1046     addr_arg.arg_type = eArgTypeAddress;
1047     addr_arg.arg_repetition = eArgRepeatPlain;
1048 
1049     // There is only one variant this argument could be; put it into the argument entry.
1050     arg1.push_back (addr_arg);
1051 
1052     // Define the first (and only) variant of this arg.
1053     value_arg.arg_type = eArgTypeValue;
1054     value_arg.arg_repetition = eArgRepeatPlus;
1055 
1056     // There is only one variant this argument could be; put it into the argument entry.
1057     arg2.push_back (value_arg);
1058 
1059     // Push the data for the first argument into the m_arguments vector.
1060     m_arguments.push_back (arg1);
1061     m_arguments.push_back (arg2);
1062 
1063     m_option_group.Append (&m_memory_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_2);
1064     m_option_group.Finalize();
1065   }
1066 
1067   virtual
1068   ~CommandObjectMemoryFind ()
1069   {
1070   }
1071 
1072   Options *
1073   GetOptions ()
1074   {
1075     return &m_option_group;
1076   }
1077 
1078 protected:
1079   virtual bool
1080   DoExecute (Args& command, CommandReturnObject &result)
1081   {
1082       // No need to check "process" for validity as eCommandRequiresProcess ensures it is valid
1083       Process *process = m_exe_ctx.GetProcessPtr();
1084 
1085       const size_t argc = command.GetArgumentCount();
1086 
1087       if (argc != 2)
1088       {
1089           result.AppendError("two addresses needed for memory find");
1090           return false;
1091       }
1092 
1093       Error error;
1094       lldb::addr_t low_addr = Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(0),LLDB_INVALID_ADDRESS,&error);
1095       if (low_addr == LLDB_INVALID_ADDRESS || error.Fail())
1096       {
1097           result.AppendError("invalid low address");
1098           return false;
1099       }
1100       lldb::addr_t high_addr = Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(1),LLDB_INVALID_ADDRESS,&error);
1101       if (high_addr == LLDB_INVALID_ADDRESS || error.Fail())
1102       {
1103           result.AppendError("invalid high address");
1104           return false;
1105       }
1106 
1107       if (high_addr <= low_addr)
1108       {
1109           result.AppendError("starting address must be smaller than ending address");
1110           return false;
1111       }
1112 
1113       lldb::addr_t found_location = LLDB_INVALID_ADDRESS;
1114 
1115       DataBufferHeap buffer;
1116 
1117       if (m_memory_options.m_string.OptionWasSet())
1118           buffer.CopyData(m_memory_options.m_string.GetStringValue(), strlen(m_memory_options.m_string.GetStringValue()));
1119       else if (m_memory_options.m_expr.OptionWasSet())
1120       {
1121           StackFrame* frame = m_exe_ctx.GetFramePtr();
1122           ValueObjectSP result_sp;
1123           if (process->GetTarget().EvaluateExpression(m_memory_options.m_expr.GetStringValue(), frame, result_sp) && 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("do not know how to deal with larger than 8 byte result types. 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("Your data was not found within the range.\n");
1181                   result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
1182               }
1183               else
1184                   result.AppendMessage("No more matches found within the range.\n");
1185               break;
1186           }
1187           result.AppendMessageWithFormat("Your data was 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         lldb::addr_t fictional_ptr = low;
1216         for (auto ptr = low;
1217              low < high;
1218              fictional_ptr++)
1219         {
1220             Error error;
1221             if (ptr == low || buffer_size == 1)
1222                 process->ReadMemory(ptr, heap.GetBytes(), buffer_size, error);
1223             else
1224             {
1225                 memmove(heap.GetBytes(), heap.GetBytes()+1, buffer_size-1);
1226                 process->ReadMemory(ptr, heap.GetBytes()+buffer_size-1, 1, error);
1227             }
1228             if (error.Fail())
1229                 return LLDB_INVALID_ADDRESS;
1230             if (memcmp(heap.GetBytes(), buffer, buffer_size) == 0)
1231                 return fictional_ptr;
1232             if (ptr == low)
1233                 ptr += buffer_size;
1234             else
1235                 ptr += 1;
1236         }
1237         return LLDB_INVALID_ADDRESS;
1238     }
1239 
1240     OptionGroupOptions m_option_group;
1241     OptionGroupFindMemory m_memory_options;
1242 };
1243 
1244 
1245 OptionDefinition
1246 g_memory_write_option_table[] =
1247 {
1248 { LLDB_OPT_SET_1, true,  "infile", 'i', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFilename, "Write memory using the contents of a file."},
1249 { LLDB_OPT_SET_1, false, "offset", 'o', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeOffset,   "Start writing bytes from an offset within the input file."},
1250 };
1251 
1252 //----------------------------------------------------------------------
1253 // Write memory to the inferior process
1254 //----------------------------------------------------------------------
1255 class CommandObjectMemoryWrite : public CommandObjectParsed
1256 {
1257 public:
1258 
1259     class OptionGroupWriteMemory : public OptionGroup
1260     {
1261     public:
1262         OptionGroupWriteMemory () :
1263             OptionGroup()
1264         {
1265         }
1266 
1267         virtual
1268         ~OptionGroupWriteMemory ()
1269         {
1270         }
1271 
1272         virtual uint32_t
1273         GetNumDefinitions ()
1274         {
1275             return sizeof (g_memory_write_option_table) / sizeof (OptionDefinition);
1276         }
1277 
1278         virtual const OptionDefinition*
1279         GetDefinitions ()
1280         {
1281             return g_memory_write_option_table;
1282         }
1283 
1284         virtual Error
1285         SetOptionValue (CommandInterpreter &interpreter,
1286                         uint32_t option_idx,
1287                         const char *option_arg)
1288         {
1289             Error error;
1290             const int short_option = g_memory_write_option_table[option_idx].short_option;
1291 
1292             switch (short_option)
1293             {
1294                 case 'i':
1295                     m_infile.SetFile (option_arg, true);
1296                     if (!m_infile.Exists())
1297                     {
1298                         m_infile.Clear();
1299                         error.SetErrorStringWithFormat("input file does not exist: '%s'", option_arg);
1300                     }
1301                     break;
1302 
1303                 case 'o':
1304                     {
1305                         bool success;
1306                         m_infile_offset = StringConvert::ToUInt64(option_arg, 0, 0, &success);
1307                         if (!success)
1308                         {
1309                             error.SetErrorStringWithFormat("invalid offset string '%s'", option_arg);
1310                         }
1311                     }
1312                     break;
1313 
1314                 default:
1315                     error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
1316                     break;
1317             }
1318             return error;
1319         }
1320 
1321         virtual void
1322         OptionParsingStarting (CommandInterpreter &interpreter)
1323         {
1324             m_infile.Clear();
1325             m_infile_offset = 0;
1326         }
1327 
1328         FileSpec m_infile;
1329         off_t m_infile_offset;
1330     };
1331 
1332     CommandObjectMemoryWrite (CommandInterpreter &interpreter) :
1333         CommandObjectParsed (interpreter,
1334                              "memory write",
1335                              "Write to the memory of the process being debugged.",
1336                              NULL,
1337                              eCommandRequiresProcess | eCommandProcessMustBeLaunched),
1338         m_option_group (interpreter),
1339         m_format_options (eFormatBytes, 1, UINT64_MAX),
1340         m_memory_options ()
1341     {
1342         CommandArgumentEntry arg1;
1343         CommandArgumentEntry arg2;
1344         CommandArgumentData addr_arg;
1345         CommandArgumentData value_arg;
1346 
1347         // Define the first (and only) variant of this arg.
1348         addr_arg.arg_type = eArgTypeAddress;
1349         addr_arg.arg_repetition = eArgRepeatPlain;
1350 
1351         // There is only one variant this argument could be; put it into the argument entry.
1352         arg1.push_back (addr_arg);
1353 
1354         // Define the first (and only) variant of this arg.
1355         value_arg.arg_type = eArgTypeValue;
1356         value_arg.arg_repetition = eArgRepeatPlus;
1357 
1358         // There is only one variant this argument could be; put it into the argument entry.
1359         arg2.push_back (value_arg);
1360 
1361         // Push the data for the first argument into the m_arguments vector.
1362         m_arguments.push_back (arg1);
1363         m_arguments.push_back (arg2);
1364 
1365         m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT, LLDB_OPT_SET_1);
1366         m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_SIZE  , LLDB_OPT_SET_1|LLDB_OPT_SET_2);
1367         m_option_group.Append (&m_memory_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_2);
1368         m_option_group.Finalize();
1369 
1370     }
1371 
1372     virtual
1373     ~CommandObjectMemoryWrite ()
1374     {
1375     }
1376 
1377     Options *
1378     GetOptions ()
1379     {
1380         return &m_option_group;
1381     }
1382 
1383     bool
1384     UIntValueIsValidForSize (uint64_t uval64, size_t total_byte_size)
1385     {
1386         if (total_byte_size > 8)
1387             return false;
1388 
1389         if (total_byte_size == 8)
1390             return true;
1391 
1392         const uint64_t max = ((uint64_t)1 << (uint64_t)(total_byte_size * 8)) - 1;
1393         return uval64 <= max;
1394     }
1395 
1396     bool
1397     SIntValueIsValidForSize (int64_t sval64, size_t total_byte_size)
1398     {
1399         if (total_byte_size > 8)
1400             return false;
1401 
1402         if (total_byte_size == 8)
1403             return true;
1404 
1405         const int64_t max = ((int64_t)1 << (uint64_t)(total_byte_size * 8 - 1)) - 1;
1406         const int64_t min = ~(max);
1407         return min <= sval64 && sval64 <= max;
1408     }
1409 
1410 protected:
1411     virtual bool
1412     DoExecute (Args& command, CommandReturnObject &result)
1413     {
1414         // No need to check "process" for validity as eCommandRequiresProcess ensures it is valid
1415         Process *process = m_exe_ctx.GetProcessPtr();
1416 
1417         const size_t argc = command.GetArgumentCount();
1418 
1419         if (m_memory_options.m_infile)
1420         {
1421             if (argc < 1)
1422             {
1423                 result.AppendErrorWithFormat ("%s takes a destination address when writing file contents.\n", m_cmd_name.c_str());
1424                 result.SetStatus(eReturnStatusFailed);
1425                 return false;
1426             }
1427         }
1428         else if (argc < 2)
1429         {
1430             result.AppendErrorWithFormat ("%s takes a destination address and at least one value.\n", m_cmd_name.c_str());
1431             result.SetStatus(eReturnStatusFailed);
1432             return false;
1433         }
1434 
1435         StreamString buffer (Stream::eBinary,
1436                              process->GetTarget().GetArchitecture().GetAddressByteSize(),
1437                              process->GetTarget().GetArchitecture().GetByteOrder());
1438 
1439         OptionValueUInt64 &byte_size_value = m_format_options.GetByteSizeValue();
1440         size_t item_byte_size = byte_size_value.GetCurrentValue();
1441 
1442         Error error;
1443         lldb::addr_t addr = Args::StringToAddress (&m_exe_ctx,
1444                                                    command.GetArgumentAtIndex(0),
1445                                                    LLDB_INVALID_ADDRESS,
1446                                                    &error);
1447 
1448         if (addr == LLDB_INVALID_ADDRESS)
1449         {
1450             result.AppendError("invalid address expression\n");
1451             result.AppendError(error.AsCString());
1452             result.SetStatus(eReturnStatusFailed);
1453             return false;
1454         }
1455 
1456         if (m_memory_options.m_infile)
1457         {
1458             size_t length = SIZE_MAX;
1459             if (item_byte_size > 1)
1460                 length = item_byte_size;
1461             lldb::DataBufferSP data_sp (m_memory_options.m_infile.ReadFileContents (m_memory_options.m_infile_offset, length));
1462             if (data_sp)
1463             {
1464                 length = data_sp->GetByteSize();
1465                 if (length > 0)
1466                 {
1467                     Error error;
1468                     size_t bytes_written = process->WriteMemory (addr, data_sp->GetBytes(), length, error);
1469 
1470                     if (bytes_written == length)
1471                     {
1472                         // All bytes written
1473                         result.GetOutputStream().Printf("%" PRIu64 " bytes were written to 0x%" PRIx64 "\n", (uint64_t)bytes_written, addr);
1474                         result.SetStatus(eReturnStatusSuccessFinishResult);
1475                     }
1476                     else if (bytes_written > 0)
1477                     {
1478                         // Some byte written
1479                         result.GetOutputStream().Printf("%" PRIu64 " bytes of %" PRIu64 " requested were written to 0x%" PRIx64 "\n", (uint64_t)bytes_written, (uint64_t)length, addr);
1480                         result.SetStatus(eReturnStatusSuccessFinishResult);
1481                     }
1482                     else
1483                     {
1484                         result.AppendErrorWithFormat ("Memory write to 0x%" PRIx64 " failed: %s.\n", addr, error.AsCString());
1485                         result.SetStatus(eReturnStatusFailed);
1486                     }
1487                 }
1488             }
1489             else
1490             {
1491                 result.AppendErrorWithFormat ("Unable to read contents of file.\n");
1492                 result.SetStatus(eReturnStatusFailed);
1493             }
1494             return result.Succeeded();
1495         }
1496         else if (item_byte_size == 0)
1497         {
1498             if (m_format_options.GetFormat() == eFormatPointer)
1499                 item_byte_size = buffer.GetAddressByteSize();
1500             else
1501                 item_byte_size = 1;
1502         }
1503 
1504         command.Shift(); // shift off the address argument
1505         uint64_t uval64;
1506         int64_t sval64;
1507         bool success = false;
1508         const size_t num_value_args = command.GetArgumentCount();
1509         for (size_t i=0; i<num_value_args; ++i)
1510         {
1511             const char *value_str = command.GetArgumentAtIndex(i);
1512 
1513             switch (m_format_options.GetFormat())
1514             {
1515             case kNumFormats:
1516             case eFormatFloat:  // TODO: add support for floats soon
1517             case eFormatCharPrintable:
1518             case eFormatBytesWithASCII:
1519             case eFormatComplex:
1520             case eFormatEnum:
1521             case eFormatUnicode16:
1522             case eFormatUnicode32:
1523             case eFormatVectorOfChar:
1524             case eFormatVectorOfSInt8:
1525             case eFormatVectorOfUInt8:
1526             case eFormatVectorOfSInt16:
1527             case eFormatVectorOfUInt16:
1528             case eFormatVectorOfSInt32:
1529             case eFormatVectorOfUInt32:
1530             case eFormatVectorOfSInt64:
1531             case eFormatVectorOfUInt64:
1532             case eFormatVectorOfFloat32:
1533             case eFormatVectorOfFloat64:
1534             case eFormatVectorOfUInt128:
1535             case eFormatOSType:
1536             case eFormatComplexInteger:
1537             case eFormatAddressInfo:
1538             case eFormatHexFloat:
1539             case eFormatInstruction:
1540             case eFormatVoid:
1541                 result.AppendError("unsupported format for writing memory");
1542                 result.SetStatus(eReturnStatusFailed);
1543                 return false;
1544 
1545             case eFormatDefault:
1546             case eFormatBytes:
1547             case eFormatHex:
1548             case eFormatHexUppercase:
1549             case eFormatPointer:
1550 
1551                 // Decode hex bytes
1552                 uval64 = StringConvert::ToUInt64(value_str, UINT64_MAX, 16, &success);
1553                 if (!success)
1554                 {
1555                     result.AppendErrorWithFormat ("'%s' is not a valid hex string value.\n", value_str);
1556                     result.SetStatus(eReturnStatusFailed);
1557                     return false;
1558                 }
1559                 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1560                 {
1561                     result.AppendErrorWithFormat("Value 0x%" PRIx64 " is too large to fit in a %" PRIu64 " byte unsigned integer value.\n", uval64, (uint64_t)item_byte_size);
1562                     result.SetStatus(eReturnStatusFailed);
1563                     return false;
1564                 }
1565                 buffer.PutMaxHex64 (uval64, item_byte_size);
1566                 break;
1567 
1568             case eFormatBoolean:
1569                 uval64 = Args::StringToBoolean(value_str, false, &success);
1570                 if (!success)
1571                 {
1572                     result.AppendErrorWithFormat ("'%s' is not a valid boolean string value.\n", value_str);
1573                     result.SetStatus(eReturnStatusFailed);
1574                     return false;
1575                 }
1576                 buffer.PutMaxHex64 (uval64, item_byte_size);
1577                 break;
1578 
1579             case eFormatBinary:
1580                 uval64 = StringConvert::ToUInt64(value_str, UINT64_MAX, 2, &success);
1581                 if (!success)
1582                 {
1583                     result.AppendErrorWithFormat ("'%s' is not a valid binary string value.\n", value_str);
1584                     result.SetStatus(eReturnStatusFailed);
1585                     return false;
1586                 }
1587                 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1588                 {
1589                     result.AppendErrorWithFormat("Value 0x%" PRIx64 " is too large to fit in a %" PRIu64 " byte unsigned integer value.\n", uval64, (uint64_t)item_byte_size);
1590                     result.SetStatus(eReturnStatusFailed);
1591                     return false;
1592                 }
1593                 buffer.PutMaxHex64 (uval64, item_byte_size);
1594                 break;
1595 
1596             case eFormatCharArray:
1597             case eFormatChar:
1598             case eFormatCString:
1599                 if (value_str[0])
1600                 {
1601                     size_t len = strlen (value_str);
1602                     // Include the NULL for C strings...
1603                     if (m_format_options.GetFormat() == eFormatCString)
1604                         ++len;
1605                     Error error;
1606                     if (process->WriteMemory (addr, value_str, len, error) == len)
1607                     {
1608                         addr += len;
1609                     }
1610                     else
1611                     {
1612                         result.AppendErrorWithFormat ("Memory write to 0x%" PRIx64 " failed: %s.\n", addr, error.AsCString());
1613                         result.SetStatus(eReturnStatusFailed);
1614                         return false;
1615                     }
1616                 }
1617                 break;
1618 
1619             case eFormatDecimal:
1620                 sval64 = StringConvert::ToSInt64(value_str, INT64_MAX, 0, &success);
1621                 if (!success)
1622                 {
1623                     result.AppendErrorWithFormat ("'%s' is not a valid signed decimal value.\n", value_str);
1624                     result.SetStatus(eReturnStatusFailed);
1625                     return false;
1626                 }
1627                 else if (!SIntValueIsValidForSize (sval64, item_byte_size))
1628                 {
1629                     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);
1630                     result.SetStatus(eReturnStatusFailed);
1631                     return false;
1632                 }
1633                 buffer.PutMaxHex64 (sval64, item_byte_size);
1634                 break;
1635 
1636             case eFormatUnsigned:
1637                 uval64 = StringConvert::ToUInt64(value_str, UINT64_MAX, 0, &success);
1638                 if (!success)
1639                 {
1640                     result.AppendErrorWithFormat ("'%s' is not a valid unsigned decimal string value.\n", value_str);
1641                     result.SetStatus(eReturnStatusFailed);
1642                     return false;
1643                 }
1644                 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1645                 {
1646                     result.AppendErrorWithFormat ("Value %" PRIu64 " is too large to fit in a %" PRIu64 " byte unsigned integer value.\n", uval64, (uint64_t)item_byte_size);
1647                     result.SetStatus(eReturnStatusFailed);
1648                     return false;
1649                 }
1650                 buffer.PutMaxHex64 (uval64, item_byte_size);
1651                 break;
1652 
1653             case eFormatOctal:
1654                 uval64 = StringConvert::ToUInt64(value_str, UINT64_MAX, 8, &success);
1655                 if (!success)
1656                 {
1657                     result.AppendErrorWithFormat ("'%s' is not a valid octal string value.\n", value_str);
1658                     result.SetStatus(eReturnStatusFailed);
1659                     return false;
1660                 }
1661                 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1662                 {
1663                     result.AppendErrorWithFormat ("Value %" PRIo64 " is too large to fit in a %" PRIu64 " byte unsigned integer value.\n", uval64, (uint64_t)item_byte_size);
1664                     result.SetStatus(eReturnStatusFailed);
1665                     return false;
1666                 }
1667                 buffer.PutMaxHex64 (uval64, item_byte_size);
1668                 break;
1669             }
1670         }
1671 
1672         if (!buffer.GetString().empty())
1673         {
1674             Error error;
1675             if (process->WriteMemory (addr, buffer.GetString().c_str(), buffer.GetString().size(), error) == buffer.GetString().size())
1676                 return true;
1677             else
1678             {
1679                 result.AppendErrorWithFormat ("Memory write to 0x%" PRIx64 " failed: %s.\n", addr, error.AsCString());
1680                 result.SetStatus(eReturnStatusFailed);
1681                 return false;
1682             }
1683         }
1684         return true;
1685     }
1686 
1687     OptionGroupOptions m_option_group;
1688     OptionGroupFormat m_format_options;
1689     OptionGroupWriteMemory m_memory_options;
1690 };
1691 
1692 //----------------------------------------------------------------------
1693 // Get malloc/free history of a memory address.
1694 //----------------------------------------------------------------------
1695 class CommandObjectMemoryHistory : public CommandObjectParsed
1696 {
1697 public:
1698 
1699     CommandObjectMemoryHistory (CommandInterpreter &interpreter) :
1700     CommandObjectParsed (interpreter,
1701                          "memory history",
1702                          "Prints out the recorded stack traces for allocation/deallocation of a memory address.",
1703                          NULL,
1704                          eCommandRequiresTarget | eCommandRequiresProcess | eCommandProcessMustBePaused | eCommandProcessMustBeLaunched)
1705     {
1706         CommandArgumentEntry arg1;
1707         CommandArgumentData addr_arg;
1708 
1709         // Define the first (and only) variant of this arg.
1710         addr_arg.arg_type = eArgTypeAddress;
1711         addr_arg.arg_repetition = eArgRepeatPlain;
1712 
1713         // There is only one variant this argument could be; put it into the argument entry.
1714         arg1.push_back (addr_arg);
1715 
1716         // Push the data for the first argument into the m_arguments vector.
1717         m_arguments.push_back (arg1);
1718     }
1719 
1720     virtual
1721     ~CommandObjectMemoryHistory ()
1722     {
1723     }
1724 
1725     virtual const char *GetRepeatCommand (Args &current_command_args, uint32_t index)
1726     {
1727         return m_cmd_name.c_str();
1728     }
1729 
1730 protected:
1731     virtual bool
1732     DoExecute (Args& command, CommandReturnObject &result)
1733     {
1734         const size_t argc = command.GetArgumentCount();
1735 
1736         if (argc == 0 || argc > 1)
1737         {
1738             result.AppendErrorWithFormat ("%s takes an address expression", m_cmd_name.c_str());
1739             result.SetStatus(eReturnStatusFailed);
1740             return false;
1741         }
1742 
1743         Error error;
1744         lldb::addr_t addr = Args::StringToAddress (&m_exe_ctx,
1745                                                    command.GetArgumentAtIndex(0),
1746                                                    LLDB_INVALID_ADDRESS,
1747                                                    &error);
1748 
1749         if (addr == LLDB_INVALID_ADDRESS)
1750         {
1751             result.AppendError("invalid address expression");
1752             result.AppendError(error.AsCString());
1753             result.SetStatus(eReturnStatusFailed);
1754             return false;
1755         }
1756 
1757         Stream *output_stream = &result.GetOutputStream();
1758 
1759         const ProcessSP &process_sp = m_exe_ctx.GetProcessSP();
1760         const MemoryHistorySP &memory_history = MemoryHistory::FindPlugin(process_sp);
1761 
1762         if (! memory_history.get())
1763         {
1764             result.AppendError("no available memory history provider");
1765             result.SetStatus(eReturnStatusFailed);
1766             return false;
1767         }
1768 
1769         HistoryThreads thread_list = memory_history->GetHistoryThreads(addr);
1770 
1771         for (auto thread : thread_list) {
1772             thread->GetStatus(*output_stream, 0, UINT32_MAX, 0);
1773         }
1774 
1775         result.SetStatus(eReturnStatusSuccessFinishResult);
1776 
1777         return true;
1778     }
1779 
1780 };
1781 
1782 
1783 //-------------------------------------------------------------------------
1784 // CommandObjectMemory
1785 //-------------------------------------------------------------------------
1786 
1787 CommandObjectMemory::CommandObjectMemory (CommandInterpreter &interpreter) :
1788     CommandObjectMultiword (interpreter,
1789                             "memory",
1790                             "A set of commands for operating on memory.",
1791                             "memory <subcommand> [<subcommand-options>]")
1792 {
1793     LoadSubCommand ("find", CommandObjectSP (new CommandObjectMemoryFind (interpreter)));
1794     LoadSubCommand ("read",  CommandObjectSP (new CommandObjectMemoryRead (interpreter)));
1795     LoadSubCommand ("write", CommandObjectSP (new CommandObjectMemoryWrite (interpreter)));
1796     LoadSubCommand ("history", CommandObjectSP (new CommandObjectMemoryHistory (interpreter)));
1797 }
1798 
1799 CommandObjectMemory::~CommandObjectMemory ()
1800 {
1801 }
1802