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