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 "lldb/lldb-python.h"
11 
12 #include "CommandObjectMemory.h"
13 
14 // C Includes
15 #include <inttypes.h>
16 
17 // C++ Includes
18 // Other libraries and framework includes
19 // Project includes
20 #include "lldb/Core/DataBufferHeap.h"
21 #include "lldb/Core/DataExtractor.h"
22 #include "lldb/Core/Debugger.h"
23 #include "lldb/Core/Module.h"
24 #include "lldb/Core/StreamString.h"
25 #include "lldb/Core/ValueObjectMemory.h"
26 #include "lldb/DataFormatters/ValueObjectPrinter.h"
27 #include "lldb/Interpreter/Args.h"
28 #include "lldb/Interpreter/CommandReturnObject.h"
29 #include "lldb/Interpreter/CommandInterpreter.h"
30 #include "lldb/Interpreter/Options.h"
31 #include "lldb/Interpreter/OptionGroupFormat.h"
32 #include "lldb/Interpreter/OptionGroupOutputFile.h"
33 #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
34 #include "lldb/Interpreter/OptionValueString.h"
35 #include "lldb/Symbol/TypeList.h"
36 #include "lldb/Target/Process.h"
37 #include "lldb/Target/StackFrame.h"
38 
39 using namespace lldb;
40 using namespace lldb_private;
41 
42 static OptionDefinition
43 g_option_table[] =
44 {
45     { LLDB_OPT_SET_1, false, "num-per-line" ,'l', OptionParser::eRequiredArgument, NULL, 0, eArgTypeNumberPerLine ,"The number of items per line to display."},
46     { LLDB_OPT_SET_2, false, "binary"       ,'b', OptionParser::eNoArgument      , 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."},
47     { LLDB_OPT_SET_3, true , "type"         ,'t', OptionParser::eRequiredArgument, NULL, 0, eArgTypeNone          ,"The name of a type to view memory as."},
48     { LLDB_OPT_SET_1|
49       LLDB_OPT_SET_2|
50       LLDB_OPT_SET_3, false, "force"        ,'r', OptionParser::eNoArgument,       NULL, 0, eArgTypeNone          ,"Necessary if reading over target.max-memory-read-size bytes."},
51 };
52 
53 
54 
55 class OptionGroupReadMemory : public OptionGroup
56 {
57 public:
58 
59     OptionGroupReadMemory () :
60         m_num_per_line (1,1),
61         m_output_as_binary (false),
62         m_view_as_type()
63     {
64     }
65 
66     virtual
67     ~OptionGroupReadMemory ()
68     {
69     }
70 
71 
72     virtual uint32_t
73     GetNumDefinitions ()
74     {
75         return sizeof (g_option_table) / sizeof (OptionDefinition);
76     }
77 
78     virtual const OptionDefinition*
79     GetDefinitions ()
80     {
81         return g_option_table;
82     }
83 
84     virtual Error
85     SetOptionValue (CommandInterpreter &interpreter,
86                     uint32_t option_idx,
87                     const char *option_arg)
88     {
89         Error error;
90         const int short_option = g_option_table[option_idx].short_option;
91 
92         switch (short_option)
93         {
94             case 'l':
95                 error = m_num_per_line.SetValueFromCString (option_arg);
96                 if (m_num_per_line.GetCurrentValue() == 0)
97                     error.SetErrorStringWithFormat("invalid value for --num-per-line option '%s'", option_arg);
98                 break;
99 
100             case 'b':
101                 m_output_as_binary = true;
102                 break;
103 
104             case 't':
105                 error = m_view_as_type.SetValueFromCString (option_arg);
106                 break;
107 
108             case 'r':
109                 m_force = true;
110                 break;
111 
112             default:
113                 error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
114                 break;
115         }
116         return error;
117     }
118 
119     virtual void
120     OptionParsingStarting (CommandInterpreter &interpreter)
121     {
122         m_num_per_line.Clear();
123         m_output_as_binary = false;
124         m_view_as_type.Clear();
125         m_force = false;
126     }
127 
128     Error
129     FinalizeSettings (Target *target, OptionGroupFormat& format_options)
130     {
131         Error error;
132         OptionValueUInt64 &byte_size_value = format_options.GetByteSizeValue();
133         OptionValueUInt64 &count_value = format_options.GetCountValue();
134         const bool byte_size_option_set = byte_size_value.OptionWasSet();
135         const bool num_per_line_option_set = m_num_per_line.OptionWasSet();
136         const bool count_option_set = format_options.GetCountValue().OptionWasSet();
137 
138         switch (format_options.GetFormat())
139         {
140             default:
141                 break;
142 
143             case eFormatBoolean:
144                 if (!byte_size_option_set)
145                     byte_size_value = 1;
146                 if (!num_per_line_option_set)
147                     m_num_per_line = 1;
148                 if (!count_option_set)
149                     format_options.GetCountValue() = 8;
150                 break;
151 
152             case eFormatCString:
153                 break;
154 
155             case eFormatInstruction:
156                 if (count_option_set)
157                     byte_size_value = target->GetArchitecture().GetMaximumOpcodeByteSize();
158                 m_num_per_line = 1;
159                 break;
160 
161             case eFormatAddressInfo:
162                 if (!byte_size_option_set)
163                     byte_size_value = target->GetArchitecture().GetAddressByteSize();
164                 m_num_per_line = 1;
165                 if (!count_option_set)
166                     format_options.GetCountValue() = 8;
167                 break;
168 
169             case eFormatPointer:
170                 byte_size_value = target->GetArchitecture().GetAddressByteSize();
171                 if (!num_per_line_option_set)
172                     m_num_per_line = 4;
173                 if (!count_option_set)
174                     format_options.GetCountValue() = 8;
175                 break;
176 
177             case eFormatBinary:
178             case eFormatFloat:
179             case eFormatOctal:
180             case eFormatDecimal:
181             case eFormatEnum:
182             case eFormatUnicode16:
183             case eFormatUnicode32:
184             case eFormatUnsigned:
185             case eFormatHexFloat:
186                 if (!byte_size_option_set)
187                     byte_size_value = 4;
188                 if (!num_per_line_option_set)
189                     m_num_per_line = 1;
190                 if (!count_option_set)
191                     format_options.GetCountValue() = 8;
192                 break;
193 
194             case eFormatBytes:
195             case eFormatBytesWithASCII:
196                 if (byte_size_option_set)
197                 {
198                     if (byte_size_value > 1)
199                         error.SetErrorStringWithFormat ("display format (bytes/bytes with ascii) conflicts with the specified byte size %" PRIu64 "\n"
200                                                         "\tconsider using a different display format or don't specify the byte size",
201                                                         byte_size_value.GetCurrentValue());
202                 }
203                 else
204                     byte_size_value = 1;
205                 if (!num_per_line_option_set)
206                     m_num_per_line = 16;
207                 if (!count_option_set)
208                     format_options.GetCountValue() = 32;
209                 break;
210             case eFormatCharArray:
211             case eFormatChar:
212             case eFormatCharPrintable:
213                 if (!byte_size_option_set)
214                     byte_size_value = 1;
215                 if (!num_per_line_option_set)
216                     m_num_per_line = 32;
217                 if (!count_option_set)
218                     format_options.GetCountValue() = 64;
219                 break;
220             case eFormatComplex:
221                 if (!byte_size_option_set)
222                     byte_size_value = 8;
223                 if (!num_per_line_option_set)
224                     m_num_per_line = 1;
225                 if (!count_option_set)
226                     format_options.GetCountValue() = 8;
227                 break;
228             case eFormatComplexInteger:
229                 if (!byte_size_option_set)
230                     byte_size_value = 8;
231                 if (!num_per_line_option_set)
232                     m_num_per_line = 1;
233                 if (!count_option_set)
234                     format_options.GetCountValue() = 8;
235                 break;
236             case eFormatHex:
237                 if (!byte_size_option_set)
238                     byte_size_value = 4;
239                 if (!num_per_line_option_set)
240                 {
241                     switch (byte_size_value)
242                     {
243                         case 1:
244                         case 2:
245                             m_num_per_line = 8;
246                             break;
247                         case 4:
248                             m_num_per_line = 4;
249                             break;
250                         case 8:
251                             m_num_per_line = 2;
252                             break;
253                         default:
254                             m_num_per_line = 1;
255                             break;
256                     }
257                 }
258                 if (!count_option_set)
259                     count_value = 8;
260                 break;
261 
262             case eFormatVectorOfChar:
263             case eFormatVectorOfSInt8:
264             case eFormatVectorOfUInt8:
265             case eFormatVectorOfSInt16:
266             case eFormatVectorOfUInt16:
267             case eFormatVectorOfSInt32:
268             case eFormatVectorOfUInt32:
269             case eFormatVectorOfSInt64:
270             case eFormatVectorOfUInt64:
271             case eFormatVectorOfFloat32:
272             case eFormatVectorOfFloat64:
273             case eFormatVectorOfUInt128:
274                 if (!byte_size_option_set)
275                     byte_size_value = 128;
276                 if (!num_per_line_option_set)
277                     m_num_per_line = 1;
278                 if (!count_option_set)
279                     count_value = 4;
280                 break;
281         }
282         return error;
283     }
284 
285     bool
286     AnyOptionWasSet () const
287     {
288         return m_num_per_line.OptionWasSet() ||
289                m_output_as_binary ||
290                m_view_as_type.OptionWasSet();
291     }
292 
293     OptionValueUInt64 m_num_per_line;
294     bool m_output_as_binary;
295     OptionValueString m_view_as_type;
296     bool m_force;
297 };
298 
299 
300 
301 //----------------------------------------------------------------------
302 // Read memory from the inferior process
303 //----------------------------------------------------------------------
304 class CommandObjectMemoryRead : public CommandObjectParsed
305 {
306 public:
307 
308     CommandObjectMemoryRead (CommandInterpreter &interpreter) :
309         CommandObjectParsed (interpreter,
310                              "memory read",
311                              "Read from the memory of the process being debugged.",
312                              NULL,
313                              eFlagRequiresTarget | eFlagProcessMustBePaused),
314         m_option_group (interpreter),
315         m_format_options (eFormatBytesWithASCII, 1, 8),
316         m_memory_options (),
317         m_outfile_options (),
318         m_varobj_options(),
319         m_next_addr(LLDB_INVALID_ADDRESS),
320         m_prev_byte_size(0),
321         m_prev_format_options (eFormatBytesWithASCII, 1, 8),
322         m_prev_memory_options (),
323         m_prev_outfile_options (),
324         m_prev_varobj_options()
325     {
326         CommandArgumentEntry arg1;
327         CommandArgumentEntry arg2;
328         CommandArgumentData start_addr_arg;
329         CommandArgumentData end_addr_arg;
330 
331         // Define the first (and only) variant of this arg.
332         start_addr_arg.arg_type = eArgTypeAddressOrExpression;
333         start_addr_arg.arg_repetition = eArgRepeatPlain;
334 
335         // There is only one variant this argument could be; put it into the argument entry.
336         arg1.push_back (start_addr_arg);
337 
338         // Define the first (and only) variant of this arg.
339         end_addr_arg.arg_type = eArgTypeAddressOrExpression;
340         end_addr_arg.arg_repetition = eArgRepeatOptional;
341 
342         // There is only one variant this argument could be; put it into the argument entry.
343         arg2.push_back (end_addr_arg);
344 
345         // Push the data for the first argument into the m_arguments vector.
346         m_arguments.push_back (arg1);
347         m_arguments.push_back (arg2);
348 
349         // Add the "--format" and "--count" options to group 1 and 3
350         m_option_group.Append (&m_format_options,
351                                OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_COUNT,
352                                LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3);
353         m_option_group.Append (&m_format_options,
354                                OptionGroupFormat::OPTION_GROUP_GDB_FMT,
355                                LLDB_OPT_SET_1 | LLDB_OPT_SET_3);
356         // Add the "--size" option to group 1 and 2
357         m_option_group.Append (&m_format_options,
358                                OptionGroupFormat::OPTION_GROUP_SIZE,
359                                LLDB_OPT_SET_1 | LLDB_OPT_SET_2);
360         m_option_group.Append (&m_memory_options);
361         m_option_group.Append (&m_outfile_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3);
362         m_option_group.Append (&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_3);
363         m_option_group.Finalize();
364     }
365 
366     virtual
367     ~CommandObjectMemoryRead ()
368     {
369     }
370 
371     Options *
372     GetOptions ()
373     {
374         return &m_option_group;
375     }
376 
377     virtual const char *GetRepeatCommand (Args &current_command_args, uint32_t index)
378     {
379         return m_cmd_name.c_str();
380     }
381 
382 protected:
383     virtual bool
384     DoExecute (Args& command, CommandReturnObject &result)
385     {
386         // No need to check "target" for validity as eFlagRequiresTarget ensures it is valid
387         Target *target = m_exe_ctx.GetTargetPtr();
388 
389         const size_t argc = command.GetArgumentCount();
390 
391         if ((argc == 0 && m_next_addr == LLDB_INVALID_ADDRESS) || argc > 2)
392         {
393             result.AppendErrorWithFormat ("%s takes a start address expression with an optional end address expression.\n", m_cmd_name.c_str());
394             result.AppendRawWarning("Expressions should be quoted if they contain spaces or other special characters.\n");
395             result.SetStatus(eReturnStatusFailed);
396             return false;
397         }
398 
399         ClangASTType clang_ast_type;
400         Error error;
401 
402         const char *view_as_type_cstr = m_memory_options.m_view_as_type.GetCurrentValue();
403         if (view_as_type_cstr && view_as_type_cstr[0])
404         {
405             // We are viewing memory as a type
406 
407             SymbolContext sc;
408             const bool exact_match = false;
409             TypeList type_list;
410             uint32_t reference_count = 0;
411             uint32_t pointer_count = 0;
412             size_t idx;
413 
414 #define ALL_KEYWORDS        \
415     KEYWORD("const")        \
416     KEYWORD("volatile")     \
417     KEYWORD("restrict")     \
418     KEYWORD("struct")       \
419     KEYWORD("class")        \
420     KEYWORD("union")
421 
422 #define KEYWORD(s) s,
423             static const char *g_keywords[] =
424             {
425                 ALL_KEYWORDS
426             };
427 #undef KEYWORD
428 
429 #define KEYWORD(s) (sizeof(s) - 1),
430             static const int g_keyword_lengths[] =
431             {
432                 ALL_KEYWORDS
433             };
434 #undef KEYWORD
435 
436 #undef ALL_KEYWORDS
437 
438             static size_t g_num_keywords = sizeof(g_keywords) / sizeof(const char *);
439             std::string type_str(view_as_type_cstr);
440 
441             // Remove all instances of g_keywords that are followed by spaces
442             for (size_t i = 0; i < g_num_keywords; ++i)
443             {
444                 const char *keyword = g_keywords[i];
445                 int keyword_len = g_keyword_lengths[i];
446 
447                 idx = 0;
448                 while ((idx = type_str.find (keyword, idx)) != std::string::npos)
449                 {
450                     if (type_str[idx + keyword_len] == ' ' || type_str[idx + keyword_len] == '\t')
451                     {
452                         type_str.erase(idx, keyword_len+1);
453                         idx = 0;
454                     }
455                     else
456                     {
457                         idx += keyword_len;
458                     }
459                 }
460             }
461             bool done = type_str.empty();
462             //
463             idx = type_str.find_first_not_of (" \t");
464             if (idx > 0 && idx != std::string::npos)
465                 type_str.erase (0, idx);
466             while (!done)
467             {
468                 // Strip trailing spaces
469                 if (type_str.empty())
470                     done = true;
471                 else
472                 {
473                     switch (type_str[type_str.size()-1])
474                     {
475                     case '*':
476                         ++pointer_count;
477                         // fall through...
478                     case ' ':
479                     case '\t':
480                         type_str.erase(type_str.size()-1);
481                         break;
482 
483                     case '&':
484                         if (reference_count == 0)
485                         {
486                             reference_count = 1;
487                             type_str.erase(type_str.size()-1);
488                         }
489                         else
490                         {
491                             result.AppendErrorWithFormat ("invalid type string: '%s'\n", view_as_type_cstr);
492                             result.SetStatus(eReturnStatusFailed);
493                             return false;
494                         }
495                         break;
496 
497                     default:
498                         done = true;
499                         break;
500                     }
501                 }
502             }
503 
504             ConstString lookup_type_name(type_str.c_str());
505             StackFrame *frame = m_exe_ctx.GetFramePtr();
506             if (frame)
507             {
508                 sc = frame->GetSymbolContext (eSymbolContextModule);
509                 if (sc.module_sp)
510                 {
511                     sc.module_sp->FindTypes (sc,
512                                              lookup_type_name,
513                                              exact_match,
514                                              1,
515                                              type_list);
516                 }
517             }
518             if (type_list.GetSize() == 0)
519             {
520                 target->GetImages().FindTypes (sc,
521                                                lookup_type_name,
522                                                exact_match,
523                                                1,
524                                                type_list);
525             }
526 
527             if (type_list.GetSize() == 0 && lookup_type_name.GetCString() && *lookup_type_name.GetCString() == '$')
528             {
529                 clang::TypeDecl *tdecl = target->GetPersistentVariables().GetPersistentType(ConstString(lookup_type_name));
530                 if (tdecl)
531                 {
532                     clang_ast_type.SetClangType(&tdecl->getASTContext(),(lldb::clang_type_t)tdecl->getTypeForDecl());
533                 }
534             }
535 
536             if (clang_ast_type.IsValid() == false)
537             {
538                 if (type_list.GetSize() == 0)
539                 {
540                     result.AppendErrorWithFormat ("unable to find any types that match the raw type '%s' for full type '%s'\n",
541                                                   lookup_type_name.GetCString(),
542                                                   view_as_type_cstr);
543                     result.SetStatus(eReturnStatusFailed);
544                     return false;
545                 }
546                 else
547                 {
548                     TypeSP type_sp (type_list.GetTypeAtIndex(0));
549                     clang_ast_type = type_sp->GetClangFullType();
550                 }
551             }
552 
553             while (pointer_count > 0)
554             {
555                 ClangASTType pointer_type = clang_ast_type.GetPointerType();
556                 if (pointer_type.IsValid())
557                     clang_ast_type = pointer_type;
558                 else
559                 {
560                     result.AppendError ("unable make a pointer type\n");
561                     result.SetStatus(eReturnStatusFailed);
562                     return false;
563                 }
564                 --pointer_count;
565             }
566 
567             m_format_options.GetByteSizeValue() = clang_ast_type.GetByteSize();
568 
569             if (m_format_options.GetByteSizeValue() == 0)
570             {
571                 result.AppendErrorWithFormat ("unable to get the byte size of the type '%s'\n",
572                                               view_as_type_cstr);
573                 result.SetStatus(eReturnStatusFailed);
574                 return false;
575             }
576 
577             if (!m_format_options.GetCountValue().OptionWasSet())
578                 m_format_options.GetCountValue() = 1;
579         }
580         else
581         {
582             error = m_memory_options.FinalizeSettings (target, m_format_options);
583         }
584 
585         // Look for invalid combinations of settings
586         if (error.Fail())
587         {
588             result.AppendError(error.AsCString());
589             result.SetStatus(eReturnStatusFailed);
590             return false;
591         }
592 
593         lldb::addr_t addr;
594         size_t total_byte_size = 0;
595         if (argc == 0)
596         {
597             // Use the last address and byte size and all options as they were
598             // if no options have been set
599             addr = m_next_addr;
600             total_byte_size = m_prev_byte_size;
601             clang_ast_type = m_prev_clang_ast_type;
602             if (!m_format_options.AnyOptionWasSet() &&
603                 !m_memory_options.AnyOptionWasSet() &&
604                 !m_outfile_options.AnyOptionWasSet() &&
605                 !m_varobj_options.AnyOptionWasSet())
606             {
607                 m_format_options = m_prev_format_options;
608                 m_memory_options = m_prev_memory_options;
609                 m_outfile_options = m_prev_outfile_options;
610                 m_varobj_options = m_prev_varobj_options;
611             }
612         }
613 
614         size_t item_count = m_format_options.GetCountValue().GetCurrentValue();
615         size_t item_byte_size = m_format_options.GetByteSizeValue().GetCurrentValue();
616         const size_t num_per_line = m_memory_options.m_num_per_line.GetCurrentValue();
617 
618         if (total_byte_size == 0)
619         {
620             total_byte_size = item_count * item_byte_size;
621             if (total_byte_size == 0)
622                 total_byte_size = 32;
623         }
624 
625         if (argc > 0)
626             addr = Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, &error);
627 
628         if (addr == LLDB_INVALID_ADDRESS)
629         {
630             result.AppendError("invalid start address expression.");
631             result.AppendError(error.AsCString());
632             result.SetStatus(eReturnStatusFailed);
633             return false;
634         }
635 
636         if (argc == 2)
637         {
638             lldb::addr_t end_addr = Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(1), LLDB_INVALID_ADDRESS, 0);
639             if (end_addr == LLDB_INVALID_ADDRESS)
640             {
641                 result.AppendError("invalid end address expression.");
642                 result.AppendError(error.AsCString());
643                 result.SetStatus(eReturnStatusFailed);
644                 return false;
645             }
646             else if (end_addr <= addr)
647             {
648                 result.AppendErrorWithFormat("end address (0x%" PRIx64 ") must be greater that the start address (0x%" PRIx64 ").\n", end_addr, addr);
649                 result.SetStatus(eReturnStatusFailed);
650                 return false;
651             }
652             else if (m_format_options.GetCountValue().OptionWasSet())
653             {
654                 result.AppendErrorWithFormat("specify either the end address (0x%" PRIx64 ") or the count (--count %lu), not both.\n", end_addr, item_count);
655                 result.SetStatus(eReturnStatusFailed);
656                 return false;
657             }
658 
659             total_byte_size = end_addr - addr;
660             item_count = total_byte_size / item_byte_size;
661         }
662 
663         uint32_t max_unforced_size = target->GetMaximumMemReadSize();
664 
665         if (total_byte_size > max_unforced_size && !m_memory_options.m_force)
666         {
667             result.AppendErrorWithFormat("Normally, \'memory read\' will not read over %" PRIu32 " bytes of data.\n",max_unforced_size);
668             result.AppendErrorWithFormat("Please use --force to override this restriction just once.\n");
669             result.AppendErrorWithFormat("or set target.max-memory-read-size if you will often need a larger limit.\n");
670             return false;
671         }
672 
673         DataBufferSP data_sp;
674         size_t bytes_read = 0;
675         if (clang_ast_type.GetOpaqueQualType())
676         {
677             // Make sure we don't display our type as ASCII bytes like the default memory read
678             if (m_format_options.GetFormatValue().OptionWasSet() == false)
679                 m_format_options.GetFormatValue().SetCurrentValue(eFormatDefault);
680 
681             bytes_read = clang_ast_type.GetByteSize() * m_format_options.GetCountValue().GetCurrentValue();
682         }
683         else if (m_format_options.GetFormatValue().GetCurrentValue() != eFormatCString)
684         {
685             data_sp.reset (new DataBufferHeap (total_byte_size, '\0'));
686             if (data_sp->GetBytes() == NULL)
687             {
688                 result.AppendErrorWithFormat ("can't allocate 0x%zx bytes for the memory read buffer, specify a smaller size to read", total_byte_size);
689                 result.SetStatus(eReturnStatusFailed);
690                 return false;
691             }
692 
693             Address address(addr, NULL);
694             bytes_read = target->ReadMemory(address, false, data_sp->GetBytes (), data_sp->GetByteSize(), error);
695             if (bytes_read == 0)
696             {
697                 const char *error_cstr = error.AsCString();
698                 if (error_cstr && error_cstr[0])
699                 {
700                     result.AppendError(error_cstr);
701                 }
702                 else
703                 {
704                     result.AppendErrorWithFormat("failed to read memory from 0x%" PRIx64 ".\n", addr);
705                 }
706                 result.SetStatus(eReturnStatusFailed);
707                 return false;
708             }
709 
710             if (bytes_read < total_byte_size)
711                 result.AppendWarningWithFormat("Not all bytes (%lu/%lu) were able to be read from 0x%" PRIx64 ".\n", bytes_read, total_byte_size, addr);
712         }
713         else
714         {
715             // we treat c-strings as a special case because they do not have a fixed size
716             if (m_format_options.GetByteSizeValue().OptionWasSet() && !m_format_options.HasGDBFormat())
717                 item_byte_size = m_format_options.GetByteSizeValue().GetCurrentValue();
718             else
719                 item_byte_size = target->GetMaximumSizeOfStringSummary();
720             if (!m_format_options.GetCountValue().OptionWasSet())
721                 item_count = 1;
722             data_sp.reset (new DataBufferHeap ((item_byte_size+1) * item_count, '\0')); // account for NULLs as necessary
723             if (data_sp->GetBytes() == NULL)
724             {
725                 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));
726                 result.SetStatus(eReturnStatusFailed);
727                 return false;
728             }
729             uint8_t *data_ptr = data_sp->GetBytes();
730             auto data_addr = addr;
731             auto count = item_count;
732             item_count = 0;
733             while (item_count < count)
734             {
735                 std::string buffer;
736                 buffer.resize(item_byte_size+1,0);
737                 Error error;
738                 size_t read = target->ReadCStringFromMemory(data_addr, &buffer[0], item_byte_size+1, error);
739                 if (error.Fail())
740                 {
741                     result.AppendErrorWithFormat("failed to read memory from 0x%" PRIx64 ".\n", addr);
742                     result.SetStatus(eReturnStatusFailed);
743                     return false;
744                 }
745                 if (item_byte_size == read)
746                 {
747                     result.AppendWarningWithFormat("unable to find a NULL terminated string at 0x%" PRIx64 ".Consider increasing the maximum read length.\n", data_addr);
748                     break;
749                 }
750                 read+=1; // account for final NULL byte
751                 memcpy(data_ptr, &buffer[0], read);
752                 data_ptr += read;
753                 data_addr += read;
754                 bytes_read += read;
755                 item_count++; // if we break early we know we only read item_count strings
756             }
757             data_sp.reset(new DataBufferHeap(data_sp->GetBytes(),bytes_read+1));
758         }
759 
760         m_next_addr = addr + bytes_read;
761         m_prev_byte_size = bytes_read;
762         m_prev_format_options = m_format_options;
763         m_prev_memory_options = m_memory_options;
764         m_prev_outfile_options = m_outfile_options;
765         m_prev_varobj_options = m_varobj_options;
766         m_prev_clang_ast_type = clang_ast_type;
767 
768         StreamFile outfile_stream;
769         Stream *output_stream = NULL;
770         const FileSpec &outfile_spec = m_outfile_options.GetFile().GetCurrentValue();
771         if (outfile_spec)
772         {
773             char path[PATH_MAX];
774             outfile_spec.GetPath (path, sizeof(path));
775 
776             uint32_t open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate;
777             const bool append = m_outfile_options.GetAppend().GetCurrentValue();
778             if (append)
779                 open_options |= File::eOpenOptionAppend;
780 
781             if (outfile_stream.GetFile ().Open (path, open_options).Success())
782             {
783                 if (m_memory_options.m_output_as_binary)
784                 {
785                     const size_t bytes_written = outfile_stream.Write (data_sp->GetBytes(), bytes_read);
786                     if (bytes_written > 0)
787                     {
788                         result.GetOutputStream().Printf ("%zi bytes %s to '%s'\n",
789                                                          bytes_written,
790                                                          append ? "appended" : "written",
791                                                          path);
792                         return true;
793                     }
794                     else
795                     {
796                         result.AppendErrorWithFormat("Failed to write %" PRIu64 " bytes to '%s'.\n", (uint64_t)bytes_read, path);
797                         result.SetStatus(eReturnStatusFailed);
798                         return false;
799                     }
800                 }
801                 else
802                 {
803                     // We are going to write ASCII to the file just point the
804                     // output_stream to our outfile_stream...
805                     output_stream = &outfile_stream;
806                 }
807             }
808             else
809             {
810                 result.AppendErrorWithFormat("Failed to open file '%s' for %s.\n", path, append ? "append" : "write");
811                 result.SetStatus(eReturnStatusFailed);
812                 return false;
813             }
814         }
815         else
816         {
817             output_stream = &result.GetOutputStream();
818         }
819 
820 
821         ExecutionContextScope *exe_scope = m_exe_ctx.GetBestExecutionContextScope();
822         if (clang_ast_type.GetOpaqueQualType())
823         {
824             for (uint32_t i = 0; i<item_count; ++i)
825             {
826                 addr_t item_addr = addr + (i * item_byte_size);
827                 Address address (item_addr);
828                 StreamString name_strm;
829                 name_strm.Printf ("0x%" PRIx64, item_addr);
830                 ValueObjectSP valobj_sp (ValueObjectMemory::Create (exe_scope,
831                                                                     name_strm.GetString().c_str(),
832                                                                     address,
833                                                                     clang_ast_type));
834                 if (valobj_sp)
835                 {
836                     Format format = m_format_options.GetFormat();
837                     if (format != eFormatDefault)
838                         valobj_sp->SetFormat (format);
839 
840                     DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(eLanguageRuntimeDescriptionDisplayVerbosityFull,format));
841 
842                     valobj_sp->Dump(*output_stream,options);
843                 }
844                 else
845                 {
846                     result.AppendErrorWithFormat ("failed to create a value object for: (%s) %s\n",
847                                                   view_as_type_cstr,
848                                                   name_strm.GetString().c_str());
849                     result.SetStatus(eReturnStatusFailed);
850                     return false;
851                 }
852             }
853             return true;
854         }
855 
856         result.SetStatus(eReturnStatusSuccessFinishResult);
857         DataExtractor data (data_sp,
858                             target->GetArchitecture().GetByteOrder(),
859                             target->GetArchitecture().GetAddressByteSize());
860 
861         Format format = m_format_options.GetFormat();
862         if ( ( (format == eFormatChar) || (format == eFormatCharPrintable) )
863             && (item_byte_size != 1))
864         {
865             // if a count was not passed, or it is 1
866             if (m_format_options.GetCountValue().OptionWasSet() == false || item_count == 1)
867             {
868                 // this turns requests such as
869                 // memory read -fc -s10 -c1 *charPtrPtr
870                 // which make no sense (what is a char of size 10?)
871                 // into a request for fetching 10 chars of size 1 from the same memory location
872                 format = eFormatCharArray;
873                 item_count = item_byte_size;
874                 item_byte_size = 1;
875             }
876             else
877             {
878                 // here we passed a count, and it was not 1
879                 // so we have a byte_size and a count
880                 // we could well multiply those, but instead let's just fail
881                 result.AppendErrorWithFormat("reading memory as characters of size %zu is not supported", item_byte_size);
882                 result.SetStatus(eReturnStatusFailed);
883                 return false;
884             }
885         }
886 
887         assert (output_stream);
888         size_t bytes_dumped = data.Dump (output_stream,
889                                          0,
890                                          format,
891                                          item_byte_size,
892                                          item_count,
893                                          num_per_line,
894                                          addr,
895                                          0,
896                                          0,
897                                          exe_scope);
898         m_next_addr = addr + bytes_dumped;
899         output_stream->EOL();
900         return true;
901     }
902 
903     OptionGroupOptions m_option_group;
904     OptionGroupFormat m_format_options;
905     OptionGroupReadMemory m_memory_options;
906     OptionGroupOutputFile m_outfile_options;
907     OptionGroupValueObjectDisplay m_varobj_options;
908     lldb::addr_t m_next_addr;
909     lldb::addr_t m_prev_byte_size;
910     OptionGroupFormat m_prev_format_options;
911     OptionGroupReadMemory m_prev_memory_options;
912     OptionGroupOutputFile m_prev_outfile_options;
913     OptionGroupValueObjectDisplay m_prev_varobj_options;
914     ClangASTType m_prev_clang_ast_type;
915 };
916 
917 
918 OptionDefinition
919 g_memory_write_option_table[] =
920 {
921 { LLDB_OPT_SET_1, true,  "infile", 'i', OptionParser::eRequiredArgument, NULL, 0, eArgTypeFilename, "Write memory using the contents of a file."},
922 { LLDB_OPT_SET_1, false, "offset", 'o', OptionParser::eRequiredArgument, NULL, 0, eArgTypeOffset,   "Start writng bytes from an offset within the input file."},
923 };
924 
925 
926 //----------------------------------------------------------------------
927 // Write memory to the inferior process
928 //----------------------------------------------------------------------
929 class CommandObjectMemoryWrite : public CommandObjectParsed
930 {
931 public:
932 
933     class OptionGroupWriteMemory : public OptionGroup
934     {
935     public:
936         OptionGroupWriteMemory () :
937             OptionGroup()
938         {
939         }
940 
941         virtual
942         ~OptionGroupWriteMemory ()
943         {
944         }
945 
946         virtual uint32_t
947         GetNumDefinitions ()
948         {
949             return sizeof (g_memory_write_option_table) / sizeof (OptionDefinition);
950         }
951 
952         virtual const OptionDefinition*
953         GetDefinitions ()
954         {
955             return g_memory_write_option_table;
956         }
957 
958         virtual Error
959         SetOptionValue (CommandInterpreter &interpreter,
960                         uint32_t option_idx,
961                         const char *option_arg)
962         {
963             Error error;
964             const int short_option = g_memory_write_option_table[option_idx].short_option;
965 
966             switch (short_option)
967             {
968                 case 'i':
969                     m_infile.SetFile (option_arg, true);
970                     if (!m_infile.Exists())
971                     {
972                         m_infile.Clear();
973                         error.SetErrorStringWithFormat("input file does not exist: '%s'", option_arg);
974                     }
975                     break;
976 
977                 case 'o':
978                     {
979                         bool success;
980                         m_infile_offset = Args::StringToUInt64(option_arg, 0, 0, &success);
981                         if (!success)
982                         {
983                             error.SetErrorStringWithFormat("invalid offset string '%s'", option_arg);
984                         }
985                     }
986                     break;
987 
988                 default:
989                     error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
990                     break;
991             }
992             return error;
993         }
994 
995         virtual void
996         OptionParsingStarting (CommandInterpreter &interpreter)
997         {
998             m_infile.Clear();
999             m_infile_offset = 0;
1000         }
1001 
1002         FileSpec m_infile;
1003         off_t m_infile_offset;
1004     };
1005 
1006     CommandObjectMemoryWrite (CommandInterpreter &interpreter) :
1007         CommandObjectParsed (interpreter,
1008                              "memory write",
1009                              "Write to the memory of the process being debugged.",
1010                              NULL,
1011                              eFlagRequiresProcess | eFlagProcessMustBeLaunched),
1012         m_option_group (interpreter),
1013         m_format_options (eFormatBytes, 1, UINT64_MAX),
1014         m_memory_options ()
1015     {
1016         CommandArgumentEntry arg1;
1017         CommandArgumentEntry arg2;
1018         CommandArgumentData addr_arg;
1019         CommandArgumentData value_arg;
1020 
1021         // Define the first (and only) variant of this arg.
1022         addr_arg.arg_type = eArgTypeAddress;
1023         addr_arg.arg_repetition = eArgRepeatPlain;
1024 
1025         // There is only one variant this argument could be; put it into the argument entry.
1026         arg1.push_back (addr_arg);
1027 
1028         // Define the first (and only) variant of this arg.
1029         value_arg.arg_type = eArgTypeValue;
1030         value_arg.arg_repetition = eArgRepeatPlus;
1031 
1032         // There is only one variant this argument could be; put it into the argument entry.
1033         arg2.push_back (value_arg);
1034 
1035         // Push the data for the first argument into the m_arguments vector.
1036         m_arguments.push_back (arg1);
1037         m_arguments.push_back (arg2);
1038 
1039         m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT, LLDB_OPT_SET_1);
1040         m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_SIZE  , LLDB_OPT_SET_1|LLDB_OPT_SET_2);
1041         m_option_group.Append (&m_memory_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_2);
1042         m_option_group.Finalize();
1043 
1044     }
1045 
1046     virtual
1047     ~CommandObjectMemoryWrite ()
1048     {
1049     }
1050 
1051     Options *
1052     GetOptions ()
1053     {
1054         return &m_option_group;
1055     }
1056 
1057     bool
1058     UIntValueIsValidForSize (uint64_t uval64, size_t total_byte_size)
1059     {
1060         if (total_byte_size > 8)
1061             return false;
1062 
1063         if (total_byte_size == 8)
1064             return true;
1065 
1066         const uint64_t max = ((uint64_t)1 << (uint64_t)(total_byte_size * 8)) - 1;
1067         return uval64 <= max;
1068     }
1069 
1070     bool
1071     SIntValueIsValidForSize (int64_t sval64, size_t total_byte_size)
1072     {
1073         if (total_byte_size > 8)
1074             return false;
1075 
1076         if (total_byte_size == 8)
1077             return true;
1078 
1079         const int64_t max = ((int64_t)1 << (uint64_t)(total_byte_size * 8 - 1)) - 1;
1080         const int64_t min = ~(max);
1081         return min <= sval64 && sval64 <= max;
1082     }
1083 
1084 protected:
1085     virtual bool
1086     DoExecute (Args& command, CommandReturnObject &result)
1087     {
1088         // No need to check "process" for validity as eFlagRequiresProcess ensures it is valid
1089         Process *process = m_exe_ctx.GetProcessPtr();
1090 
1091         const size_t argc = command.GetArgumentCount();
1092 
1093         if (m_memory_options.m_infile)
1094         {
1095             if (argc < 1)
1096             {
1097                 result.AppendErrorWithFormat ("%s takes a destination address when writing file contents.\n", m_cmd_name.c_str());
1098                 result.SetStatus(eReturnStatusFailed);
1099                 return false;
1100             }
1101         }
1102         else if (argc < 2)
1103         {
1104             result.AppendErrorWithFormat ("%s takes a destination address and at least one value.\n", m_cmd_name.c_str());
1105             result.SetStatus(eReturnStatusFailed);
1106             return false;
1107         }
1108 
1109         StreamString buffer (Stream::eBinary,
1110                              process->GetTarget().GetArchitecture().GetAddressByteSize(),
1111                              process->GetTarget().GetArchitecture().GetByteOrder());
1112 
1113         OptionValueUInt64 &byte_size_value = m_format_options.GetByteSizeValue();
1114         size_t item_byte_size = byte_size_value.GetCurrentValue();
1115 
1116         Error error;
1117         lldb::addr_t addr = Args::StringToAddress (&m_exe_ctx,
1118                                                    command.GetArgumentAtIndex(0),
1119                                                    LLDB_INVALID_ADDRESS,
1120                                                    &error);
1121 
1122         if (addr == LLDB_INVALID_ADDRESS)
1123         {
1124             result.AppendError("invalid address expression\n");
1125             result.AppendError(error.AsCString());
1126             result.SetStatus(eReturnStatusFailed);
1127             return false;
1128         }
1129 
1130         if (m_memory_options.m_infile)
1131         {
1132             size_t length = SIZE_MAX;
1133             if (item_byte_size > 0)
1134                 length = item_byte_size;
1135             lldb::DataBufferSP data_sp (m_memory_options.m_infile.ReadFileContents (m_memory_options.m_infile_offset, length));
1136             if (data_sp)
1137             {
1138                 length = data_sp->GetByteSize();
1139                 if (length > 0)
1140                 {
1141                     Error error;
1142                     size_t bytes_written = process->WriteMemory (addr, data_sp->GetBytes(), length, error);
1143 
1144                     if (bytes_written == length)
1145                     {
1146                         // All bytes written
1147                         result.GetOutputStream().Printf("%" PRIu64 " bytes were written to 0x%" PRIx64 "\n", (uint64_t)bytes_written, addr);
1148                         result.SetStatus(eReturnStatusSuccessFinishResult);
1149                     }
1150                     else if (bytes_written > 0)
1151                     {
1152                         // Some byte written
1153                         result.GetOutputStream().Printf("%" PRIu64 " bytes of %" PRIu64 " requested were written to 0x%" PRIx64 "\n", (uint64_t)bytes_written, (uint64_t)length, addr);
1154                         result.SetStatus(eReturnStatusSuccessFinishResult);
1155                     }
1156                     else
1157                     {
1158                         result.AppendErrorWithFormat ("Memory write to 0x%" PRIx64 " failed: %s.\n", addr, error.AsCString());
1159                         result.SetStatus(eReturnStatusFailed);
1160                     }
1161                 }
1162             }
1163             else
1164             {
1165                 result.AppendErrorWithFormat ("Unable to read contents of file.\n");
1166                 result.SetStatus(eReturnStatusFailed);
1167             }
1168             return result.Succeeded();
1169         }
1170         else if (item_byte_size == 0)
1171         {
1172             if (m_format_options.GetFormat() == eFormatPointer)
1173                 item_byte_size = buffer.GetAddressByteSize();
1174             else
1175                 item_byte_size = 1;
1176         }
1177 
1178         command.Shift(); // shift off the address argument
1179         uint64_t uval64;
1180         int64_t sval64;
1181         bool success = false;
1182         const size_t num_value_args = command.GetArgumentCount();
1183         for (size_t i=0; i<num_value_args; ++i)
1184         {
1185             const char *value_str = command.GetArgumentAtIndex(i);
1186 
1187             switch (m_format_options.GetFormat())
1188             {
1189             case kNumFormats:
1190             case eFormatFloat:  // TODO: add support for floats soon
1191             case eFormatCharPrintable:
1192             case eFormatBytesWithASCII:
1193             case eFormatComplex:
1194             case eFormatEnum:
1195             case eFormatUnicode16:
1196             case eFormatUnicode32:
1197             case eFormatVectorOfChar:
1198             case eFormatVectorOfSInt8:
1199             case eFormatVectorOfUInt8:
1200             case eFormatVectorOfSInt16:
1201             case eFormatVectorOfUInt16:
1202             case eFormatVectorOfSInt32:
1203             case eFormatVectorOfUInt32:
1204             case eFormatVectorOfSInt64:
1205             case eFormatVectorOfUInt64:
1206             case eFormatVectorOfFloat32:
1207             case eFormatVectorOfFloat64:
1208             case eFormatVectorOfUInt128:
1209             case eFormatOSType:
1210             case eFormatComplexInteger:
1211             case eFormatAddressInfo:
1212             case eFormatHexFloat:
1213             case eFormatInstruction:
1214             case eFormatVoid:
1215                 result.AppendError("unsupported format for writing memory");
1216                 result.SetStatus(eReturnStatusFailed);
1217                 return false;
1218 
1219             case eFormatDefault:
1220             case eFormatBytes:
1221             case eFormatHex:
1222             case eFormatHexUppercase:
1223             case eFormatPointer:
1224 
1225                 // Decode hex bytes
1226                 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 16, &success);
1227                 if (!success)
1228                 {
1229                     result.AppendErrorWithFormat ("'%s' is not a valid hex string value.\n", value_str);
1230                     result.SetStatus(eReturnStatusFailed);
1231                     return false;
1232                 }
1233                 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1234                 {
1235                     result.AppendErrorWithFormat ("Value 0x%" PRIx64 " is too large to fit in a %lu byte unsigned integer value.\n", uval64, item_byte_size);
1236                     result.SetStatus(eReturnStatusFailed);
1237                     return false;
1238                 }
1239                 buffer.PutMaxHex64 (uval64, item_byte_size);
1240                 break;
1241 
1242             case eFormatBoolean:
1243                 uval64 = Args::StringToBoolean(value_str, false, &success);
1244                 if (!success)
1245                 {
1246                     result.AppendErrorWithFormat ("'%s' is not a valid boolean string value.\n", value_str);
1247                     result.SetStatus(eReturnStatusFailed);
1248                     return false;
1249                 }
1250                 buffer.PutMaxHex64 (uval64, item_byte_size);
1251                 break;
1252 
1253             case eFormatBinary:
1254                 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 2, &success);
1255                 if (!success)
1256                 {
1257                     result.AppendErrorWithFormat ("'%s' is not a valid binary string value.\n", value_str);
1258                     result.SetStatus(eReturnStatusFailed);
1259                     return false;
1260                 }
1261                 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1262                 {
1263                     result.AppendErrorWithFormat ("Value 0x%" PRIx64 " is too large to fit in a %lu byte unsigned integer value.\n", uval64, item_byte_size);
1264                     result.SetStatus(eReturnStatusFailed);
1265                     return false;
1266                 }
1267                 buffer.PutMaxHex64 (uval64, item_byte_size);
1268                 break;
1269 
1270             case eFormatCharArray:
1271             case eFormatChar:
1272             case eFormatCString:
1273                 if (value_str[0])
1274                 {
1275                     size_t len = strlen (value_str);
1276                     // Include the NULL for C strings...
1277                     if (m_format_options.GetFormat() == eFormatCString)
1278                         ++len;
1279                     Error error;
1280                     if (process->WriteMemory (addr, value_str, len, error) == len)
1281                     {
1282                         addr += len;
1283                     }
1284                     else
1285                     {
1286                         result.AppendErrorWithFormat ("Memory write to 0x%" PRIx64 " failed: %s.\n", addr, error.AsCString());
1287                         result.SetStatus(eReturnStatusFailed);
1288                         return false;
1289                     }
1290                 }
1291                 break;
1292 
1293             case eFormatDecimal:
1294                 sval64 = Args::StringToSInt64(value_str, INT64_MAX, 0, &success);
1295                 if (!success)
1296                 {
1297                     result.AppendErrorWithFormat ("'%s' is not a valid signed decimal value.\n", value_str);
1298                     result.SetStatus(eReturnStatusFailed);
1299                     return false;
1300                 }
1301                 else if (!SIntValueIsValidForSize (sval64, item_byte_size))
1302                 {
1303                     result.AppendErrorWithFormat ("Value %" PRIi64 " is too large or small to fit in a %lu byte signed integer value.\n", sval64, item_byte_size);
1304                     result.SetStatus(eReturnStatusFailed);
1305                     return false;
1306                 }
1307                 buffer.PutMaxHex64 (sval64, item_byte_size);
1308                 break;
1309 
1310             case eFormatUnsigned:
1311                 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 0, &success);
1312                 if (!success)
1313                 {
1314                     result.AppendErrorWithFormat ("'%s' is not a valid unsigned decimal string value.\n", value_str);
1315                     result.SetStatus(eReturnStatusFailed);
1316                     return false;
1317                 }
1318                 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1319                 {
1320                     result.AppendErrorWithFormat ("Value %" PRIu64 " is too large to fit in a %lu byte unsigned integer value.\n", uval64, item_byte_size);
1321                     result.SetStatus(eReturnStatusFailed);
1322                     return false;
1323                 }
1324                 buffer.PutMaxHex64 (uval64, item_byte_size);
1325                 break;
1326 
1327             case eFormatOctal:
1328                 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 8, &success);
1329                 if (!success)
1330                 {
1331                     result.AppendErrorWithFormat ("'%s' is not a valid octal string value.\n", value_str);
1332                     result.SetStatus(eReturnStatusFailed);
1333                     return false;
1334                 }
1335                 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1336                 {
1337                     result.AppendErrorWithFormat ("Value %" PRIo64 " is too large to fit in a %lu byte unsigned integer value.\n", uval64, item_byte_size);
1338                     result.SetStatus(eReturnStatusFailed);
1339                     return false;
1340                 }
1341                 buffer.PutMaxHex64 (uval64, item_byte_size);
1342                 break;
1343             }
1344         }
1345 
1346         if (!buffer.GetString().empty())
1347         {
1348             Error error;
1349             if (process->WriteMemory (addr, buffer.GetString().c_str(), buffer.GetString().size(), error) == buffer.GetString().size())
1350                 return true;
1351             else
1352             {
1353                 result.AppendErrorWithFormat ("Memory write to 0x%" PRIx64 " failed: %s.\n", addr, error.AsCString());
1354                 result.SetStatus(eReturnStatusFailed);
1355                 return false;
1356             }
1357         }
1358         return true;
1359     }
1360 
1361     OptionGroupOptions m_option_group;
1362     OptionGroupFormat m_format_options;
1363     OptionGroupWriteMemory m_memory_options;
1364 };
1365 
1366 
1367 //-------------------------------------------------------------------------
1368 // CommandObjectMemory
1369 //-------------------------------------------------------------------------
1370 
1371 CommandObjectMemory::CommandObjectMemory (CommandInterpreter &interpreter) :
1372     CommandObjectMultiword (interpreter,
1373                             "memory",
1374                             "A set of commands for operating on memory.",
1375                             "memory <subcommand> [<subcommand-options>]")
1376 {
1377     LoadSubCommand ("read",  CommandObjectSP (new CommandObjectMemoryRead (interpreter)));
1378     LoadSubCommand ("write", CommandObjectSP (new CommandObjectMemoryWrite (interpreter)));
1379 }
1380 
1381 CommandObjectMemory::~CommandObjectMemory ()
1382 {
1383 }
1384