xref: /llvm-project/lldb/source/Commands/CommandObjectMemory.cpp (revision e0d378b3340c67c774b0e27593347d9c521fe86f)
1 //===-- CommandObjectMemory.cpp ---------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "CommandObjectMemory.h"
11 
12 // C Includes
13 // C++ Includes
14 // Other libraries and framework includes
15 // Project includes
16 #include "lldb/Core/DataBufferHeap.h"
17 #include "lldb/Core/DataExtractor.h"
18 #include "lldb/Core/Debugger.h"
19 #include "lldb/Core/StreamString.h"
20 #include "lldb/Interpreter/Args.h"
21 #include "lldb/Interpreter/CommandReturnObject.h"
22 #include "lldb/Interpreter/CommandInterpreter.h"
23 #include "lldb/Interpreter/Options.h"
24 #include "lldb/Target/Process.h"
25 
26 using namespace lldb;
27 using namespace lldb_private;
28 
29 //----------------------------------------------------------------------
30 // Read memory from the inferior process
31 //----------------------------------------------------------------------
32 class CommandObjectMemoryRead : public CommandObject
33 {
34 public:
35 
36     class CommandOptions : public Options
37     {
38     public:
39         CommandOptions () :
40             Options()
41         {
42             ResetOptionValues();
43         }
44 
45         virtual
46         ~CommandOptions ()
47         {
48         }
49 
50         virtual Error
51         SetOptionValue (int option_idx, const char *option_arg)
52         {
53             Error error;
54             char short_option = (char) m_getopt_table[option_idx].val;
55 
56             switch (short_option)
57             {
58             case 'f':
59                 error = Args::StringToFormat (option_arg, m_format);
60 
61                 switch (m_format)
62                 {
63                 default:
64                     break;
65 
66                 case eFormatBoolean:
67                     if (m_byte_size == 0)
68                         m_byte_size = 1;
69                     if (m_num_per_line == 0)
70                         m_num_per_line = 1;
71                     break;
72 
73                 case eFormatCString:
74                     if (m_num_per_line == 0)
75                         m_num_per_line = 1;
76                     break;
77 
78                 case eFormatPointer:
79                     break;
80 
81                 case eFormatBinary:
82                 case eFormatFloat:
83                 case eFormatOctal:
84                 case eFormatDecimal:
85                 case eFormatEnum:
86                 case eFormatUnicode16:
87                 case eFormatUnicode32:
88                 case eFormatUnsigned:
89                     if (m_byte_size == 0)
90                         m_byte_size = 4;
91                     if (m_num_per_line == 0)
92                         m_num_per_line = 1;
93                     break;
94 
95                 case eFormatBytes:
96                 case eFormatBytesWithASCII:
97                 case eFormatChar:
98                 case eFormatCharPrintable:
99                     if (m_byte_size == 0)
100                         m_byte_size = 1;
101                     break;
102                 case eFormatComplex:
103                     if (m_byte_size == 0)
104                         m_byte_size = 8;
105                     break;
106                 case eFormatHex:
107                     if (m_byte_size == 0)
108                         m_byte_size = 4;
109                     break;
110 
111                 case eFormatVectorOfChar:
112                 case eFormatVectorOfSInt8:
113                 case eFormatVectorOfUInt8:
114                 case eFormatVectorOfSInt16:
115                 case eFormatVectorOfUInt16:
116                 case eFormatVectorOfSInt32:
117                 case eFormatVectorOfUInt32:
118                 case eFormatVectorOfSInt64:
119                 case eFormatVectorOfUInt64:
120                 case eFormatVectorOfFloat32:
121                 case eFormatVectorOfFloat64:
122                 case eFormatVectorOfUInt128:
123                     break;
124                 }
125                 break;
126 
127             case 'l':
128                 m_num_per_line = Args::StringToUInt32 (option_arg, 0);
129                 if (m_num_per_line == 0)
130                     error.SetErrorStringWithFormat("Invalid value for --num-per-line option '%s'. Must be positive integer value.\n", option_arg);
131                 break;
132 
133             case 'c':
134                 m_count = Args::StringToUInt32 (option_arg, 0);
135                 if (m_count == 0)
136                     error.SetErrorStringWithFormat("Invalid value for --count option '%s'. Must be positive integer value.\n", option_arg);
137                 break;
138 
139             case 's':
140                 m_byte_size = Args::StringToUInt32 (option_arg, 0);
141                 if (m_byte_size == 0)
142                     error.SetErrorStringWithFormat("Invalid value for --size option '%s'. Must be positive integer value.\n", option_arg);
143                 break;
144 
145             case 'o':
146                 m_outfile_filespec.SetFile (option_arg, true);
147                 break;
148 
149             case 'b':
150                 m_output_as_binary = true;
151                 break;
152 
153             case 'a':
154                 m_append_to_outfile = true;
155                 break;
156 
157             default:
158                 error.SetErrorStringWithFormat("Unrecognized short option '%c'.\n", short_option);
159                 break;
160             }
161             return error;
162         }
163 
164         void
165         ResetOptionValues ()
166         {
167             Options::ResetOptionValues();
168             m_format = eFormatBytesWithASCII;
169             m_byte_size = 0;
170             m_count = 0;
171             m_num_per_line = 0;
172             m_outfile_filespec.Clear();
173             m_append_to_outfile = false;
174             m_output_as_binary = false;
175         }
176 
177         const OptionDefinition*
178         GetDefinitions ()
179         {
180             return g_option_table;
181         }
182 
183         // Options table: Required for subclasses of Options.
184 
185         static OptionDefinition g_option_table[];
186 
187         // Instance variables to hold the values for command options.
188         lldb::Format m_format;
189         uint32_t m_byte_size;
190         uint32_t m_count;
191         uint32_t m_num_per_line;
192         FileSpec m_outfile_filespec;
193         bool m_append_to_outfile;
194         bool m_output_as_binary;
195     };
196 
197     CommandObjectMemoryRead (CommandInterpreter &interpreter) :
198         CommandObject (interpreter,
199                        "memory read",
200                        "Read from the memory of the process being debugged.",
201                        NULL,
202                        eFlagProcessMustBeLaunched)
203     {
204         CommandArgumentEntry arg1;
205         CommandArgumentEntry arg2;
206         CommandArgumentData start_addr_arg;
207         CommandArgumentData end_addr_arg;
208 
209         // Define the first (and only) variant of this arg.
210         start_addr_arg.arg_type = eArgTypeStartAddress;
211         start_addr_arg.arg_repetition = eArgRepeatPlain;
212 
213         // There is only one variant this argument could be; put it into the argument entry.
214         arg1.push_back (start_addr_arg);
215 
216         // Define the first (and only) variant of this arg.
217         end_addr_arg.arg_type = eArgTypeEndAddress;
218         end_addr_arg.arg_repetition = eArgRepeatOptional;
219 
220         // There is only one variant this argument could be; put it into the argument entry.
221         arg2.push_back (end_addr_arg);
222 
223         // Push the data for the first argument into the m_arguments vector.
224         m_arguments.push_back (arg1);
225         m_arguments.push_back (arg2);
226     }
227 
228     virtual
229     ~CommandObjectMemoryRead ()
230     {
231     }
232 
233     Options *
234     GetOptions ()
235     {
236         return &m_options;
237     }
238 
239     virtual bool
240     Execute (Args& command,
241              CommandReturnObject &result)
242     {
243         Process *process = m_interpreter.GetDebugger().GetExecutionContext().process;
244         if (process == NULL)
245         {
246             result.AppendError("need a process to read memory");
247             result.SetStatus(eReturnStatusFailed);
248             return false;
249         }
250         const size_t argc = command.GetArgumentCount();
251 
252         if (argc == 0 || argc > 2)
253         {
254             result.AppendErrorWithFormat ("%s takes 1 or two args.\n", m_cmd_name.c_str());
255             result.SetStatus(eReturnStatusFailed);
256             return false;
257         }
258 
259         size_t item_byte_size = m_options.m_byte_size;
260         if (item_byte_size == 0)
261         {
262             if (m_options.m_format == eFormatPointer)
263                 item_byte_size = process->GetTarget().GetArchitecture().GetAddressByteSize();
264             else
265                 item_byte_size = 1;
266         }
267 
268         size_t item_count = m_options.m_count;
269 
270         size_t num_per_line = m_options.m_num_per_line;
271         if (num_per_line == 0)
272         {
273             num_per_line = (16/item_byte_size);
274             if (num_per_line == 0)
275                 num_per_line = 1;
276         }
277 
278         size_t total_byte_size = m_options.m_count * item_byte_size;
279         if (total_byte_size == 0)
280             total_byte_size = 32;
281 
282         lldb::addr_t addr = Args::StringToUInt64(command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, 0);
283 
284         if (addr == LLDB_INVALID_ADDRESS)
285         {
286             result.AppendErrorWithFormat("invalid start address string '%s'.\n", command.GetArgumentAtIndex(0));
287             result.SetStatus(eReturnStatusFailed);
288             return false;
289         }
290 
291         if (argc == 2)
292         {
293             lldb::addr_t end_addr = Args::StringToUInt64(command.GetArgumentAtIndex(1), LLDB_INVALID_ADDRESS, 0);
294             if (end_addr == LLDB_INVALID_ADDRESS)
295             {
296                 result.AppendErrorWithFormat("Invalid end address string '%s'.\n", command.GetArgumentAtIndex(1));
297                 result.SetStatus(eReturnStatusFailed);
298                 return false;
299             }
300             else if (end_addr <= addr)
301             {
302                 result.AppendErrorWithFormat("End address (0x%llx) must be greater that the start address (0x%llx).\n", end_addr, addr);
303                 result.SetStatus(eReturnStatusFailed);
304                 return false;
305             }
306             else if (item_count != 0)
307             {
308                 result.AppendErrorWithFormat("Specify either the end address (0x%llx) or the count (--count %u), not both.\n", end_addr, item_count);
309                 result.SetStatus(eReturnStatusFailed);
310                 return false;
311             }
312 
313             total_byte_size = end_addr - addr;
314             item_count = total_byte_size / item_byte_size;
315         }
316         else
317         {
318             if (item_count == 0)
319                 item_count = 32;
320         }
321 
322         DataBufferSP data_sp(new DataBufferHeap (total_byte_size, '\0'));
323         Error error;
324         size_t bytes_read = process->ReadMemory(addr, data_sp->GetBytes (), data_sp->GetByteSize(), error);
325         if (bytes_read == 0)
326         {
327             result.AppendWarningWithFormat("Read from 0x%llx failed.\n", addr);
328             result.AppendError(error.AsCString());
329             result.SetStatus(eReturnStatusFailed);
330             return false;
331         }
332 
333         if (bytes_read < total_byte_size)
334             result.AppendWarningWithFormat("Not all bytes (%u/%u) were able to be read from 0x%llx.\n", bytes_read, total_byte_size, addr);
335 
336         result.SetStatus(eReturnStatusSuccessFinishResult);
337         DataExtractor data (data_sp,
338                             process->GetTarget().GetArchitecture().GetByteOrder(),
339                             process->GetTarget().GetArchitecture().GetAddressByteSize());
340 
341         StreamFile outfile_stream;
342         Stream *output_stream = NULL;
343 
344         if (m_options.m_outfile_filespec)
345         {
346             char path[PATH_MAX];
347             m_options.m_outfile_filespec.GetPath (path, sizeof(path));
348             char mode[16] = { 'w', '\0' };
349             if (m_options.m_append_to_outfile)
350                 mode[0] = 'a';
351 
352             if (outfile_stream.GetFile ().Open (path, File::eOpenOptionWrite | File::eOpenOptionCanCreate).Success())
353             {
354                 if (m_options.m_output_as_binary)
355                 {
356                     int bytes_written = outfile_stream.Write (data_sp->GetBytes(), bytes_read);
357                     if (bytes_written > 0)
358                     {
359                         result.GetOutputStream().Printf ("%i bytes %s to '%s'\n",
360                                                          bytes_written,
361                                                          m_options.m_append_to_outfile ? "appended" : "written",
362                                                          path);
363                         return true;
364                     }
365                     else
366                     {
367                         result.AppendErrorWithFormat("Failed to write %zu bytes to '%s'.\n", bytes_read, path);
368                         result.SetStatus(eReturnStatusFailed);
369                         return false;
370                     }
371                 }
372                 else
373                 {
374                     // We are going to write ASCII to the file just point the
375                     // output_stream to our outfile_stream...
376                     output_stream = &outfile_stream;
377                 }
378             }
379             else
380             {
381                 result.AppendErrorWithFormat("Failed to open file '%s' with a mode of '%s'.\n", path, mode);
382                 result.SetStatus(eReturnStatusFailed);
383                 return false;
384             }
385         }
386         else
387         {
388             output_stream = &result.GetOutputStream();
389         }
390 
391         assert (output_stream);
392         data.Dump (output_stream,
393                    0,
394                    m_options.m_format,
395                    item_byte_size,
396                    item_count,
397                    num_per_line,
398                    addr,
399                    0,
400                    0);
401         output_stream->EOL();
402         return true;
403     }
404 
405 protected:
406     CommandOptions m_options;
407 };
408 
409 #define SET1 LLDB_OPT_SET_1
410 #define SET2 LLDB_OPT_SET_2
411 
412 OptionDefinition
413 CommandObjectMemoryRead::CommandOptions::g_option_table[] =
414 {
415 { SET1       , false, "format",       'f', required_argument, NULL, 0, eArgTypeFormat,       "The format that will be used to display the memory. Defaults to bytes with ASCII (--format=Y)."},
416 { SET1       , false, "size",         's', required_argument, NULL, 0, eArgTypeByteSize,     "The size in bytes to use when displaying with the selected format."},
417 { SET1       , false, "num-per-line", 'l', required_argument, NULL, 0, eArgTypeNumberPerLine,"The number of items per line to display."},
418 { SET1       , false, "count",        'c', required_argument, NULL, 0, eArgTypeCount,        "The number of total items to display."},
419 { SET1 | SET2, false, "outfile",      'o', required_argument, NULL, 0, eArgTypeFilename,     "Dump memory read results into a file."},
420 { SET1 | SET2, false, "append",       'a', no_argument,       NULL, 0, eArgTypeNone,         "Append memory read results to 'outfile'."},
421 {        SET2, 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."},
422 { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
423 };
424 
425 #undef SET1
426 #undef SET2
427 
428 //----------------------------------------------------------------------
429 // Write memory to the inferior process
430 //----------------------------------------------------------------------
431 class CommandObjectMemoryWrite : public CommandObject
432 {
433 public:
434 
435     class CommandOptions : public Options
436     {
437     public:
438         CommandOptions () :
439             Options()
440         {
441             ResetOptionValues();
442         }
443 
444         virtual
445         ~CommandOptions ()
446         {
447         }
448 
449         virtual Error
450         SetOptionValue (int option_idx, const char *option_arg)
451         {
452             Error error;
453             char short_option = (char) m_getopt_table[option_idx].val;
454             switch (short_option)
455             {
456             case 'f':
457                 error = Args::StringToFormat (option_arg, m_format);
458                 break;
459 
460             case 's':
461                 m_byte_size = Args::StringToUInt32 (option_arg, 0);
462                 if (m_byte_size == 0)
463                     error.SetErrorStringWithFormat("Invalid value for --size option '%s'.  Must be positive integer value.\n", option_arg);
464                 break;
465 
466             case 'i':
467                 m_infile.SetFile (option_arg, true);
468                 if (!m_infile.Exists())
469                 {
470                     m_infile.Clear();
471                     error.SetErrorStringWithFormat("Input file does not exist: '%s'\n", option_arg);
472                 }
473                 break;
474 
475             case 'o':
476                 {
477                     bool success;
478                     m_infile_offset = Args::StringToUInt64(option_arg, 0, 0, &success);
479                     if (!success)
480                     {
481                         error.SetErrorStringWithFormat("Invalid offset string '%s'\n", option_arg);
482                     }
483                 }
484                 break;
485 
486             default:
487                 error.SetErrorStringWithFormat("Unrecognized short option '%c'\n", short_option);
488                 break;
489             }
490             return error;
491         }
492 
493         void
494         ResetOptionValues ()
495         {
496             Options::ResetOptionValues();
497             m_format = eFormatBytes;
498             m_byte_size = 1;
499             m_infile.Clear();
500             m_infile_offset = 0;
501         }
502 
503         const OptionDefinition*
504         GetDefinitions ()
505         {
506             return g_option_table;
507         }
508 
509         // Options table: Required for subclasses of Options.
510 
511         static OptionDefinition g_option_table[];
512 
513         // Instance variables to hold the values for command options.
514         lldb::Format m_format;
515         uint32_t m_byte_size;
516         FileSpec m_infile;
517         off_t m_infile_offset;
518     };
519 
520     CommandObjectMemoryWrite (CommandInterpreter &interpreter) :
521         CommandObject (interpreter,
522                        "memory write",
523                        "Write to the memory of the process being debugged.",
524                        //"memory write [<cmd-options>] <addr> [value1 value2 ...]",
525                        NULL,
526                        eFlagProcessMustBeLaunched)
527     {
528         CommandArgumentEntry arg1;
529         CommandArgumentEntry arg2;
530         CommandArgumentData addr_arg;
531         CommandArgumentData value_arg;
532 
533         // Define the first (and only) variant of this arg.
534         addr_arg.arg_type = eArgTypeAddress;
535         addr_arg.arg_repetition = eArgRepeatPlain;
536 
537         // There is only one variant this argument could be; put it into the argument entry.
538         arg1.push_back (addr_arg);
539 
540         // Define the first (and only) variant of this arg.
541         value_arg.arg_type = eArgTypeValue;
542         value_arg.arg_repetition = eArgRepeatPlus;
543 
544         // There is only one variant this argument could be; put it into the argument entry.
545         arg2.push_back (value_arg);
546 
547         // Push the data for the first argument into the m_arguments vector.
548         m_arguments.push_back (arg1);
549         m_arguments.push_back (arg2);
550     }
551 
552     virtual
553     ~CommandObjectMemoryWrite ()
554     {
555     }
556 
557     Options *
558     GetOptions ()
559     {
560         return &m_options;
561     }
562 
563     bool
564     UIntValueIsValidForSize (uint64_t uval64, size_t total_byte_size)
565     {
566         if (total_byte_size > 8)
567             return false;
568 
569         if (total_byte_size == 8)
570             return true;
571 
572         const uint64_t max = ((uint64_t)1 << (uint64_t)(total_byte_size * 8)) - 1;
573         return uval64 <= max;
574     }
575 
576     bool
577     SIntValueIsValidForSize (int64_t sval64, size_t total_byte_size)
578     {
579         if (total_byte_size > 8)
580             return false;
581 
582         if (total_byte_size == 8)
583             return true;
584 
585         const int64_t max = ((int64_t)1 << (uint64_t)(total_byte_size * 8 - 1)) - 1;
586         const int64_t min = ~(max);
587         return min <= sval64 && sval64 <= max;
588     }
589 
590     virtual bool
591     Execute (Args& command,
592              CommandReturnObject &result)
593     {
594         Process *process = m_interpreter.GetDebugger().GetExecutionContext().process;
595         if (process == NULL)
596         {
597             result.AppendError("need a process to read memory");
598             result.SetStatus(eReturnStatusFailed);
599             return false;
600         }
601 
602         const size_t argc = command.GetArgumentCount();
603 
604         if (m_options.m_infile)
605         {
606             if (argc < 1)
607             {
608                 result.AppendErrorWithFormat ("%s takes a destination address when writing file contents.\n", m_cmd_name.c_str());
609                 result.SetStatus(eReturnStatusFailed);
610                 return false;
611             }
612         }
613         else if (argc < 2)
614         {
615             result.AppendErrorWithFormat ("%s takes a destination address and at least one value.\n", m_cmd_name.c_str());
616             result.SetStatus(eReturnStatusFailed);
617             return false;
618         }
619 
620         StreamString buffer (Stream::eBinary,
621                              process->GetTarget().GetArchitecture().GetAddressByteSize(),
622                              process->GetTarget().GetArchitecture().GetByteOrder());
623 
624         size_t item_byte_size = m_options.m_byte_size;
625 
626         lldb::addr_t addr = Args::StringToUInt64(command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, 0);
627 
628         if (addr == LLDB_INVALID_ADDRESS)
629         {
630             result.AppendErrorWithFormat("Invalid address string '%s'.\n", command.GetArgumentAtIndex(0));
631             result.SetStatus(eReturnStatusFailed);
632             return false;
633         }
634 
635         if (m_options.m_infile)
636         {
637             size_t length = SIZE_MAX;
638             if (m_options.m_byte_size > 0)
639                 length = m_options.m_byte_size;
640             lldb::DataBufferSP data_sp (m_options.m_infile.ReadFileContents (m_options.m_infile_offset, length));
641             if (data_sp)
642             {
643                 length = data_sp->GetByteSize();
644                 if (length > 0)
645                 {
646                     Error error;
647                     size_t bytes_written = process->WriteMemory (addr, data_sp->GetBytes(), length, error);
648 
649                     if (bytes_written == length)
650                     {
651                         // All bytes written
652                         result.GetOutputStream().Printf("%zu bytes were written to 0x%llx\n", bytes_written, addr);
653                         result.SetStatus(eReturnStatusSuccessFinishResult);
654                     }
655                     else if (bytes_written > 0)
656                     {
657                         // Some byte written
658                         result.GetOutputStream().Printf("%zu bytes of %zu requested were written to 0x%llx\n", bytes_written, length, addr);
659                         result.SetStatus(eReturnStatusSuccessFinishResult);
660                     }
661                     else
662                     {
663                         result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString());
664                         result.SetStatus(eReturnStatusFailed);
665                     }
666                 }
667             }
668             else
669             {
670                 result.AppendErrorWithFormat ("Unable to read contents of file.\n");
671                 result.SetStatus(eReturnStatusFailed);
672             }
673             return result.Succeeded();
674         }
675         else if (m_options.m_byte_size == 0)
676         {
677             if (m_options.m_format == eFormatPointer)
678                 item_byte_size = buffer.GetAddressByteSize();
679             else
680                 item_byte_size = 1;
681         }
682 
683         command.Shift(); // shift off the address argument
684         uint64_t uval64;
685         int64_t sval64;
686         bool success = false;
687         const uint32_t num_value_args = command.GetArgumentCount();
688         uint32_t i;
689         for (i=0; i<num_value_args; ++i)
690         {
691             const char *value_str = command.GetArgumentAtIndex(i);
692 
693             switch (m_options.m_format)
694             {
695             case eFormatFloat:  // TODO: add support for floats soon
696             case eFormatCharPrintable:
697             case eFormatBytesWithASCII:
698             case eFormatComplex:
699             case eFormatEnum:
700             case eFormatUnicode16:
701             case eFormatUnicode32:
702             case eFormatVectorOfChar:
703             case eFormatVectorOfSInt8:
704             case eFormatVectorOfUInt8:
705             case eFormatVectorOfSInt16:
706             case eFormatVectorOfUInt16:
707             case eFormatVectorOfSInt32:
708             case eFormatVectorOfUInt32:
709             case eFormatVectorOfSInt64:
710             case eFormatVectorOfUInt64:
711             case eFormatVectorOfFloat32:
712             case eFormatVectorOfFloat64:
713             case eFormatVectorOfUInt128:
714             case eFormatOSType:
715             case eFormatComplexInteger:
716                 result.AppendError("unsupported format for writing memory");
717                 result.SetStatus(eReturnStatusFailed);
718                 return false;
719 
720             case eFormatDefault:
721             case eFormatBytes:
722             case eFormatHex:
723             case eFormatPointer:
724 
725                 // Decode hex bytes
726                 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 16, &success);
727                 if (!success)
728                 {
729                     result.AppendErrorWithFormat ("'%s' is not a valid hex string value.\n", value_str);
730                     result.SetStatus(eReturnStatusFailed);
731                     return false;
732                 }
733                 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
734                 {
735                     result.AppendErrorWithFormat ("Value 0x%llx is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size);
736                     result.SetStatus(eReturnStatusFailed);
737                     return false;
738                 }
739                 buffer.PutMaxHex64 (uval64, item_byte_size);
740                 break;
741 
742             case eFormatBoolean:
743                 uval64 = Args::StringToBoolean(value_str, false, &success);
744                 if (!success)
745                 {
746                     result.AppendErrorWithFormat ("'%s' is not a valid boolean string value.\n", value_str);
747                     result.SetStatus(eReturnStatusFailed);
748                     return false;
749                 }
750                 buffer.PutMaxHex64 (uval64, item_byte_size);
751                 break;
752 
753             case eFormatBinary:
754                 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 2, &success);
755                 if (!success)
756                 {
757                     result.AppendErrorWithFormat ("'%s' is not a valid binary string value.\n", value_str);
758                     result.SetStatus(eReturnStatusFailed);
759                     return false;
760                 }
761                 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
762                 {
763                     result.AppendErrorWithFormat ("Value 0x%llx is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size);
764                     result.SetStatus(eReturnStatusFailed);
765                     return false;
766                 }
767                 buffer.PutMaxHex64 (uval64, item_byte_size);
768                 break;
769 
770             case eFormatChar:
771             case eFormatCString:
772                 if (value_str[0])
773                 {
774                     size_t len = strlen (value_str);
775                     // Include the NULL for C strings...
776                     if (m_options.m_format == eFormatCString)
777                         ++len;
778                     Error error;
779                     if (process->WriteMemory (addr, value_str, len, error) == len)
780                     {
781                         addr += len;
782                     }
783                     else
784                     {
785                         result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString());
786                         result.SetStatus(eReturnStatusFailed);
787                         return false;
788                     }
789                 }
790                 break;
791 
792             case eFormatDecimal:
793                 sval64 = Args::StringToSInt64(value_str, INT64_MAX, 0, &success);
794                 if (!success)
795                 {
796                     result.AppendErrorWithFormat ("'%s' is not a valid signed decimal value.\n", value_str);
797                     result.SetStatus(eReturnStatusFailed);
798                     return false;
799                 }
800                 else if (!SIntValueIsValidForSize (sval64, item_byte_size))
801                 {
802                     result.AppendErrorWithFormat ("Value %lli is too large or small to fit in a %u byte signed integer value.\n", sval64, item_byte_size);
803                     result.SetStatus(eReturnStatusFailed);
804                     return false;
805                 }
806                 buffer.PutMaxHex64 (sval64, item_byte_size);
807                 break;
808 
809             case eFormatUnsigned:
810                 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 0, &success);
811                 if (!success)
812                 {
813                     result.AppendErrorWithFormat ("'%s' is not a valid unsigned decimal string value.\n", value_str);
814                     result.SetStatus(eReturnStatusFailed);
815                     return false;
816                 }
817                 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
818                 {
819                     result.AppendErrorWithFormat ("Value %llu is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size);
820                     result.SetStatus(eReturnStatusFailed);
821                     return false;
822                 }
823                 buffer.PutMaxHex64 (uval64, item_byte_size);
824                 break;
825 
826             case eFormatOctal:
827                 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 8, &success);
828                 if (!success)
829                 {
830                     result.AppendErrorWithFormat ("'%s' is not a valid octal string value.\n", value_str);
831                     result.SetStatus(eReturnStatusFailed);
832                     return false;
833                 }
834                 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
835                 {
836                     result.AppendErrorWithFormat ("Value %llo is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size);
837                     result.SetStatus(eReturnStatusFailed);
838                     return false;
839                 }
840                 buffer.PutMaxHex64 (uval64, item_byte_size);
841                 break;
842             }
843         }
844 
845         if (!buffer.GetString().empty())
846         {
847             Error error;
848             if (process->WriteMemory (addr, buffer.GetString().c_str(), buffer.GetString().size(), error) == buffer.GetString().size())
849                 return true;
850             else
851             {
852                 result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString());
853                 result.SetStatus(eReturnStatusFailed);
854                 return false;
855             }
856         }
857         return true;
858     }
859 
860 protected:
861     CommandOptions m_options;
862 };
863 
864 #define SET1 LLDB_OPT_SET_1
865 #define SET2 LLDB_OPT_SET_2
866 
867 OptionDefinition
868 CommandObjectMemoryWrite::CommandOptions::g_option_table[] =
869 {
870 { SET1       , false, "format", 'f', required_argument, NULL, 0, eArgTypeFormat,   "The format value types that will be decoded and written to memory."},
871 { SET1 | SET2, false, "size",   's', required_argument, NULL, 0, eArgTypeByteSize, "The size in bytes of the values to write to memory."},
872 {        SET2, true,  "infile", 'i', required_argument, NULL, 0, eArgTypeFilename, "Write memory using the contents of a file."},
873 {        SET2, false, "offset", 'o', required_argument, NULL, 0, eArgTypeOffset,   "Start writng bytes from an offset within the input file."},
874 { 0          , false, NULL    ,  0 , 0                , NULL, 0, eArgTypeNone,     NULL }
875 };
876 
877 #undef SET1
878 #undef SET2
879 
880 //-------------------------------------------------------------------------
881 // CommandObjectMemory
882 //-------------------------------------------------------------------------
883 
884 CommandObjectMemory::CommandObjectMemory (CommandInterpreter &interpreter) :
885     CommandObjectMultiword (interpreter,
886                             "memory",
887                             "A set of commands for operating on memory.",
888                             "memory <subcommand> [<subcommand-options>]")
889 {
890     LoadSubCommand ("read",  CommandObjectSP (new CommandObjectMemoryRead (interpreter)));
891     LoadSubCommand ("write", CommandObjectSP (new CommandObjectMemoryWrite (interpreter)));
892 }
893 
894 CommandObjectMemory::~CommandObjectMemory ()
895 {
896 }
897